您的位置:首页 > 其它

同余方程组——中国剩余定理の板子

2017-01-13 07:37 113 查看

中国剩余定理

中国剩余定理(CRT)是求解形如

x≡a1(mod m1)x≡a2(mod m2)x≡a3(mod m3)......x≡ak(mod mk)

的同余方程组的一种算法。一般的中国剩余定理要求m1,m2,...,mk两两互质,但它的扩展算法可以处理不互质的情况。

一般情况

当m1,m2,...,mk两两互质的时候,上面提到的同余方程组一定有整数解。设M=m1×m2×...×mk,也就是M是所有模数的最小公倍数,那么上面的同余方程组在模M的意义下有唯一解。

那么中国剩余定理又是如何求解这个同余方程组的呢?首先我们要知道一个东西就是:如果一个整数N满足N mod m=k,那么对于任意整数v,有(v×N) mod m≡(v×k) mod m。这个东西正确性比较显然啦,设N=r×m+k然后往里一代就可以证明了。

那么仍然回到上面的同余方程组,如果我们能够求解出这样的一些N1,N2,...,Nk,满足对于每一个Ni,它对除了mi以外的所有m取模都是0,但除以mi余数为1。构造出这样的一堆东西有什么用呢?结合上面说的那个东西我们可以发现,令N=a1N1+a2N2+...+akNk,则N就是同余方程的一个合法整数解。因为每个Ni累加进去不会破坏其它模数的余数而只会影响它自己的mi的余数,所以这样是正确的。

于是问题就变成了如何求解Ni。仍然用M表示所有模数的最小公倍数,将Mmi表示为Mi,那么Ni=Mi×x。又因为Ni mod mi=1,所以Ni=y×mi+1。把这两种表示Ni的方法一联立就有了Mi×x−y×mi=1。

这里就体现了我们保证模数互质的重要性。因为模数们两两互质,所以mi和Mi也互质,那么就可以把上面含有x,y的不定方程写作Mi∗x+mi∗y=gcd(Mi,mi)。

这个式子就是经典的扩展欧几里得能够解决的式子了。因为我们要求的是x,那么相当于求Mi在模mi意义下的逆元。这个方程一定是有解的,那么我们可以对每一个Mi和mi都求一下对应的x,同时维护一个sum,每次累加上x×Mi×ai,最后就能求出一个解。

而因为我们可以注意到M是所有模数的最小公倍数,它模所有mi都是0,所以求出的这个解加上M的整数倍仍然是合法解。那么如果要求的是最小正整数解,我们只需要把一开始求出的解对M取模就可以了。

long long CRT(long long M){
long long sum=0,tmp,v;
for (int i=1;i<=cnt;i++){
tmp=M/m[i];
v=getInv(tmp,m[i]);
sum=(sum+tmp*a[i]*v)%M;
}
return sum;
}


扩展——模数不互质

如果同余方程组扩展到模数不互质的情况,这个时候首先不能用扩展欧几里得直接求逆元,并且还有可能会出现无解的情况。这个时候就不能用上面那种方法求解了,我们需要把方程两两合并化简。

设有两个方程x≡a1(mod m1),x≡a2(mod m2)。把这两个方程展开写成x=a1+n1×m1,x=a2+n2×m2。

这两个方程左边都是x,把它们两个联立就变成了n1×m1+a1=n2×m2+a2。再移项化简一下就得到了n1×m1−n2×m2=a2−a1。

这又是一个形如ax+by=c的不定方程。结合扩展欧几里得算法可以判断如果(a2−a1) mod gcd(m1,m2)≠0的话这个同余方程组就是无解的。设gcd(m1,m2)=d,我们可以用扩展欧几里得求出n1在模m2d意义下的值N。但这显然不一定是真正的n1,所以我们把n1写作y×m2d+N。

把n1代入第一个方程x=a1+n1×m1就可以得到x=a1+(y×m2d+N)×m1,把括号展开就可以得到x=a1+N×m1+y×m1×m2d。

这里y虽然是一个未知数,但我们可以把这个方程写作同余方程的形式,就是x≡a1+N×m1(mod m1×m2d)。那么这两个方程就合并成了一个方程,得到了新的余数和新的模数。那么我们就可以把给出的所有方程两两合并成新的方程,最后只剩下一个方程的时候当然就可以很方便地求解了。

bool merge(long long &a1,long long &m1,long long a2,long long m2){
long long c,d,x,a3,m3;
c=a2-a1;d=gcd(m1,m2);
if (c%d!=0) return false;
c=c/d;m1=m1/d;m2=m2/d;
x=getinv(m1,m2);
x=(x*c)%m2;
x=x*(m1*d)+a1;
m3=m1*m2*d;
a3=(x%m3+m3)%m3;
a1=a3;m1=m3;
return true;
}
long long CRT(){
long long A=a[1],M=r[1];
for (int i=2;i<=n;i++)
if (!merge(A,M,a[i],r[i]))
return -1;
return (A%M+M)%M;
}


应用

中国剩余定理最常用的版本还是模数互质的版本,因为有些题目中我们为了利用某些性质必须保证模数是质数或模数与什么东西互质,而如果它偏偏给了一个不是质数的模数,我们就可以把这个模数分解质因数,对每个质因数求出结果以后再用中国剩余定理合并。这个时候显然模数们都是互质的,用第一种形式就可以了。

简单的练习题:

POJ-1006 Biorhythms

POJ-2891 Strange Way to Express Integers

HDU-1573 X问题
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  中国剩余定理