中国剩余定理
中国剩余定理(CRT)是求解形如
的同余方程组的一种算法。一般的中国剩余定理要求 m1,m2,...,mk 两两互质,但它的扩展算法可以处理不互质的情况。
一般情况
当 m1,m2,...,mk 两两互质的时候,上面提到的同余方程组一定有整数解。设 M=m1×m2×...×mk ,也就是M是所有模数的最小公倍数,那么上面的同余方程组在模M的意义下有唯一解。
那么中国剩余定理又是如何求解这个同余方程组的呢?首先我们要知道一个东西就是:如果一个整数
N
满足
那么仍然回到上面的同余方程组,如果我们能够求解出这样的一些
N1,N2,...,Nk
,满足对于每一个
Ni
,它对除了
mi
以外的所有
m
取模都是0,但除以
于是问题就变成了如何求解
Ni
。仍然用
M
表示所有模数的最小公倍数,将
这里就体现了我们保证模数互质的重要性。因为模数们两两互质,所以 mi 和 Mi 也互质,那么就可以把上面含有 x,y 的不定方程写作 Mi∗x+mi∗y=gcd(Mi,mi) 。
这个式子就是经典的扩展欧几里得能够解决的式子了。因为我们要求的是
x
,那么相当于求
而因为我们可以注意到
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
,把它们两个联立就变成了
这又是一个形如
ax+by=c
的不定方程。结合扩展欧几里得算法可以判断如果
(a2−a1) mod gcd(m1,m2)≠0
的话这个同余方程组就是无解的。设
gcd(m1,m2)=d
,我们可以用扩展欧几里得求出
n1
在模
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问题