POJ 2891 Strange Way to Express Integers 中国剩余定理 数论 exgcd
http://poj.org/problem?id=2891
题意就是孙子算经里那个定理的基础描述不过换了数字和约束条件的个数……
https://blog.csdn.net/HownoneHe/article/details/52186204
这个博客提供了互质情况下的代码以及由此递推出的(另一个版本的)非互质情况下的代码。
假如给出m[n],a[n]分别代表要求的除数和余数:
互质情况下:
( 做n次 ) 对不包含m[i]的所有m求积 ( 互质的数的最小公倍数 ) , exgcd求出来逆元后*a[i], 然后对这n个结果求和取模.
设M为不包含m[i]的所有m的积,
那么 (M*x)%m[i]=1 --> (M*x)=1+m[i]*y --> (M*x)-m[i]*y=1
exgcd后的M*x就是单位1 ( 逆元 ) 了.
非互质情况下:
M被分解质因子,重复质因子的指数都变为1(最小公倍数),然后做同样操作。
我这里写的是一个相对优化的代码(博客中的第二个版本),使用的空间更小,求最小公倍数更加方便,也更不容易过程中溢出,嗯读一下代码应该就明白了。
我总觉得我以前写过中国剩余定理啊为什么现在这么详细解释……
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #define LL long long 7 const LL maxn=300010; 8 LL n; 9 void exgcd(LL a,LL b,LL &d,LL &x,LL &y){ 10 if(!b){ 11 x=1;y=0;d=a; 12 return; 13 }exgcd(b,a%b,d,x,y); 14 LL z=x;x=y; 15 y=z-(LL)(a/b)*y; 16 } 17 int main(){ 18 while(~scanf("%lld",&n)){ 19 LL mc=0,ac=0,m1=0,a1=0,f=0; 20 for(int i=1;i<=n;i++){ 21 scanf("%lld%lld",&m1,&a1); 22 if(f)continue; 23 if(i==1){mc=m1;ac=a1;continue;} 24 LL x,y,d,c=a1-ac; exgcd(mc,m1,d,x,y); 25 if(c%d){f=1;continue;} 26 x=(((x*(c/d))%m1)+m1)%m1; 27 ac+=mc*x; 28 mc=mc/d*m1; 29 ac=ac%mc; 30 } 31 if(f)printf("-1\n"); 32 else printf("%lld\n",ac); 33 } 34 }