中国剩余定理在ACM中主要用来解方程
中国剩余定理需要用到扩展欧几里得算法
就从欧几里得算法开始讲起
LL gcd(LL a,LL b)
{
Return b==0?a:gcd(b,a%b);
}
b==0时我们返回a作为最大公约数,现在就是判断a和b的最大公约数是不是等于b和a%b的最大公约数
设a除b=k……r
第一步:令c=gcd(a,b) 则设a=mc b=nc
第二步:根据前提r=a-kb=mc-knc=(m-kn)c
第三步:根据第二步结果可知c也是r 的因数
第四步:判定m-kn与n互质(否则,可设m-kn=xd,n=yd d>1,则m=kn+xd=kyd+xd=(ky+x)d,则a=mc=(ky+x)dc b=nc=ycd 故a与b的最大公约数成为cd,与前面矛盾)
然后是扩展欧几里得算法
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
LL gcd=exgcd(b,a%b,x,y);
LL tmp=x;
x=y;
y=tmp-a/b*x;
return gcd;
}
扩展欧几里得算法用于求解ax+by=gcd(a,b)中的x和y
怎么求解呢
利用前面的性质gcd(a,b)=gcd(b,a%b)
ax+by=gcd(a,b)=gcd(b,a%b)=b*x1+a%b*y1
我们可以把a%b写成 (a-a/b*b) 代入上式
ax+by=b*x1+(a-a/b*b)*y1=a*y1+b*(x1-a/b*y1)
对比系数得出 x=y1 y=x1-a/b*y1
故而我们可以写出上述递归函数求解x和y
我们在b=0的时候返回x=1 y=0 这个列个式子 很好理解的 就不写了
然后就是应用扩展欧几里得定理求解线性同余方程组了
a1=a[0];b1=b[0];
for(int i=1;i<m;i++)
{
a2=a[i];b2=b[i];
LL gcd=exgcd(a1,a2,x,y);
if((b2-b1)%gcd)
{
flag=1;
break;
}
LL t=a2/gcd;
x=(x*(b2-b1))/gcd;
x=(x%t+t)%t;
b1=a1*x+b1;
a1=(a1*a2)/gcd;
b1=(b1%a1+a1)%a1;
}
N=ai (mod bi)
我们取两组数来从小见大吧
N mod a1=b1
N mod a2=b2
可以改写成
N=a1*x+b1
N=a2*y+b2
我们求解出x或者y中的任意一个就可以求得解了
a1*x+b1=a2*y+b2 移项
a1*x-a2*y=b2-b1……1
是不是和之前写的扩展欧几里得算法很像
a*x1+b*y1=gcd(a,b)……2
我们从这里引入扩展欧几里得算法的应用求解ax+by=c的整数解(整数解存在的前提是c|gcd(a,b) 即c%gcd(a,b)==0)
结合2式很容易得出 1式中x=(b2-b1)/gcd(a1,a2)*x1(为什么a2可以变成正的,无非就是y换个正负号么。。)
这样我们就得出了方程1 x的一个解 但x未必是最小的正解
我们可以得出 设我们上面得出的解为x0 y0
那么通解可以表示为 x=x0+(a2/gcd)*t
y=y0+(a1/gcd)*t 其中gcd=gcd(a1,a2)
于是我们去求最小的正数x t=a2/gcd x=(x%t+t)%t
然后最终N的值就是a1*x+b1 我们把它保存在b1中 然后a1去lcm(a1,a2) 得到最小的正数b1 b1=(b1%a1+a1)%a1 这样我们就得到了最终的答案 a1是循环节 b1是最小的正数N