#include <stdio.h> #include <math.h> #include <string.h> #include <algorithm> using namespace std; #define LL long long LL p[13],r[13],n; void gcd(LL a,LL b,LL &d,LL &x,LL &y)//扩展欧几里德算法求ax+by=gcd(a,b)当然一组整数解 { //其中d是最大公约数 if(!b){d=a;x=1;y=0;} else{gcd(b,a%b,d,y,x);y-=x*(a/b);} } LL Chinese_Remainder() { LL i,s=1,m,x,y,d,ans=0; for(i=0;i<n;i++) s=s*p[i]; for(i=0;i<n;i++) { m=s/p[i]; gcd(p[i],m,d,x,y); //p[i]与m互质,p[i]*x+my=1(y必定不是0),因而my%p[i]==1,myr[i]%p[i]=r[i];m为其余数相乘 ans=(ans+y*m*r[i])%s;//所以总和ans只有对应的myr[i]有余数,其余都整除 } return (ans%s+s)%s; } int main() { LL T,t,tt=0,i; scanf("%lld",&T); while(T--) { scanf("%lld",&n); for(i=0;i<n;i++) scanf("%lld%lld",&p[i],&r[i]); t=Chinese_Remainder(); printf("Case %lld: %lld\n",++tt,t); } return 0; } /* 中国剩余定理(孙子定理):求M使,M%A=a,M%B=b,M%C=c,...,M%Z=z。其中A,B,C,...,Z互质 先求第一个数:m=(B*C**...*Z);A与m互质,由扩展欧几里德算法求得(x,y)使得A*x+m*y=1 所以(A*x+my)%A-->my%A=1-->amy%A=a,amy%(B,C,D,...)=0; 求出其余的数并求和ans=a*m1*y1+b*m2*y2+c*m3*y3...就是解。由于很大,要对n=(A*B*C*...*Z)取余,不影响结果 */
poj2891 是中国剩余定理的一般形式,其中M%m1=r1,M%m2=r2...;m1,m2...互相之间不互质
只能每输入一个求一次解,类似dp
#include <stdio.h> #include <string.h> void gcd(__int64 a,__int64 b,__int64 &d,__int64 &x,__int64 &y) {//a*x+b*y=gcd(a,b)=d;(x,y)为其一组整数解 if(!b){d=a;x=1;y=0;} else{ gcd(b,a%b,d,y,x);y-=x*(a/b);} } int main() { __int64 n,m1,r1,m2,r2,flag=0; while(scanf("%I64d",&n)!=EOF) { __int64 i,j,k,d,x,y,c,t; scanf("%I64d%I64d",&m1,&r1); flag=0; for(i=1;i<n;i++) { scanf("%I64d%I64d",&m2,&r2); if(flag)continue; gcd(m1,m2,d,x,y);//d=gcd(m1,m2);x*m1+y*m2=d; c=r2-r1; if(c%d)//对于方程m1*x+m2*y=c,如果c不是d的倍数就无整数解 { flag=1; continue; } t=m2/d;//对于方程m1x+m2y=c=r2-r1,若(x0,y0)是一组整数解,那么(x0+k*m2/d,y0-k*m1/d)也是一组整数解(k为任意整数) //其中x0=x*c/d,y0=x*c/d; x=(c/d*x%t+t)%t;//保证x0是正数,因为x+k*t是解,(x%t+t)%t也必定是正数解(必定存在某个k使得(x%t+t)%t=x+k*t) r1=m1*x+r1;//新求的r1就是前i组的解,Mi=m1*x+M(i-1)=r2-m2*y(m1为前i个m的最小公倍数);对m2取余时,余数为r2; //对以前的m取余时,Mi%m=m1*x%m+M(i-1)%m=M(i-1)%m=r m1=m1*m2/d; } if(flag)printf("-1\n"); else printf("%I64d\n",r1); } return 0; }