欢迎各位持续向我私信好的 CRT 及 ExCRT 的题目/qq
中国剩余定理(Chinese Remainder Theorem, CRT)和扩展中国剩余定理(Extension of Chinese Remainder Theorem, ExCRT)学习笔记。
对于任意两个
我们希望能够求出它的最小非负整数解
我们定义几个变量的值。首先存在
此时我们计算序列
对于模板题「曹冲养猪」我们可以用如下代码进行求解:
#include<bits/stdc++.h>
#define int long long
int n,a[99],m[99],al[99],mul=1,ans;
int Exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}int d=Exgcd(b,a%b,x,y),t=x;
x=y;
y=t-(a/b)*y;
return d;
}signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&m[i],&a[i]);
mul=mul*m[i];
}for(int i=1;i<=n;i++){
al[i]=mul/m[i];
int x=0,y=0;
Exgcd(al[i],m[i],x,y);
if(x<0)x+=m[i];
ans+=a[i]*al[i]*x;
}printf("%lld\n",ans%mul);
return 0;
}
为什么这组解是正确的?我们不妨令
因此,我们可以确认对于每一个
我们考虑一种情况,如果模数并非两两互质,又应该怎么解决这个问题?实际上,如果我们寄希望于对 CRT 的内容进行修改于扩展,绝对会遭致当头棒喝——CRT 的核心在于求取逆元构造解,而在不互质的情况下这个逆元甚至可能不存在,因此我们只能完全抛弃先前的思想,更进一步地讨论新的方法。
考虑一件事情:我们解寻常方程组的方式是进行合并方程,从而实现化简的需求。在正常的研究当中,我们希望能够从两个方程组之间的合并方法进行归纳,然后我们就可以进一步推广到所有方程。这其中有两个难点,首先在于两个特殊例子的合并法则能否推广至全体(且为什么),另一个在于这样的变化是否是等价的——合并结果是否包含原来的所有解?是否不会多出新的解?这是需要证明的。
那么我们从简单的模式开始。
存在同余方程
确认此时对于右边两个式子的未知数有且仅有
我们任取一个
当存在
因此我们可以确定
代码可以实现:
#include<bits/stdc++.h>
#define int __int128
using namespace std;
int Exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}int d=Exgcd(b,a%b,x,y),t=x;
x=y;
y=t-(a/b)*y;
return d;
}bool flag;
int a1,a2,n1,n2;
void Trivial(){
int d=a2-a1;
int g,x,y;
g=Exgcd(n1,n2,x,y);
if(!(d%g)){
x=((x*d/g)%(n2/g)+(n2/g))%(n2/g);
a1=x*n1 + a1;
n1=(n1*n2)/g;
}else flag=1;
}long long n,as[100001],ns[100001];
int ExCRT(){
a1=as[0];n1=ns[0];
for(int i=1;i<n;i++){
a2=as[i];
n2=ns[i];
Trivial();
if(flag)return -1;
}return a1;
}signed main() {
cin>>n;
flag=false;
for(int i=0;i<n;i++)
cin>>ns[i]>>as[i];
cout<<(long long)ExCRT()<<endl;
return 0;
}