中国剩余定理模板
/* 中国剩余定理简单解释: 定理:如果a%b=c 那么(a+kb)%b=c 首先看一个简单例子:对于x%3=2,x%5=3,x%7=2,求解x(最小) 令m[i]=3,5,7 a[i]=2,3,2; 我们假设n1%3=2,但是又要满足另外两个方程的解,那么n1必须是5,7的倍数 同理n2%3=2且n2必须是3,7的倍数,n3%7=2且n3必须是3,5的倍数 那么(n1+n2+n3)就是满足这三个同余方程的一个解 因此x=(n1+n2+n3)%M 那么如何求n1,n2,n3呢?可通过欧几里得算法求解 令M=LCD(m[i])即这三个数的最小公倍数,又因为它们互质所以M=m[i]*m[2]*m[3]; Ni=M/m[i],那么ni=Ni*t使得Ni*t%m[i]=a[i] 得到方程Ni*t+m[i]*y=a[i],t,y为要求的变量 ni=Ni*t*a[i],因为通过欧几里得算出来的t只满足Ni*t%m[i]=1,因此还需要乘以a[i] */ #include <iostream> #include<cstdio> #include<cstring> using namespace std; //欧几里得算法 __int64 extend_euclid(__int64 a,__int64 b,__int64 &x,__int64 &y) { if(b==0) { x=1;y=0; return a; } __int64 d = extend_euclid(b,a%b,x,y); __int64 t = x; x=y; y=t-a/b*y; return d; } //中国剩余定理求解x=a[i](mod(m[i]))---也就是x%m[i]=a[i],只针对m[i]互质情况 //参数len,同余方程的个数,m[i],a[i]从1开始,int类型根据题意更改 __int64 cnt(int len,__int64 m[],__int64 a[]) { __int64 M = 1,ans = 0; for(int i=1;i<=len;i++) M*=m[i]; __int64 x,y; for(int i=1;i<=len;i++) { __int64 Ni = M/m[i]; extend_euclid(Ni,m[i],x,y); x=(x%m[i]+m[i])%m[i];//保证x为最小的正数解 ans=(ans+x*a[i]*Ni)%M; } if(ans<0) ans=ans+M; return ans; } int main() { int n; __int64 m[10],a[10]; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%I64d%I64d",&m[i],&a[i]); printf("%I64d\n",cnt(n,m,a)); return 0; }