蛋疼的一题啊,为了这题先去学了中国剩余定理(比较简单),然后又去学了拓展欧几里得,推了好久的公式,终于弄明白了,然后又去研究怎么求解线性方程组,终于把这题过了。
拓展欧几里得我就不讲了,讲一下这题怎么解方程组的,网上只有代码,没有说明白怎么推的。我们先可以先找两个同余方程 设通解为N,N=r1(mod(m1)),N=r2(mod(m2)),显然可以化为k1*m1+r1=k2*m2+r2;--->k1*m1+(-k2*m2)=r2-r1;设a=m1,b=m2,x=k1,y=(-k2),c=r2-r1方程可写为ax+by=c;由欧几里得解得x即可,那么将x化为原方程的最小正整数解,(x*(c/d)%(b/d)+(b/d))%(b/d);这里看不懂的去看解模线性方程。那么这个x就是原方程的最小整数解。所以N=a*(x+n*(b/d))+r1====N=(a*b/d)*n+(a*x+r1),这里只有n为未知数所以又是一个N=(a*x+r1)(mod(a*b/d))的式子,然后只要不断的将两个式变成一个式子,最后就能解出这个方程组的解。
Run ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
5296255 | 2012-01-26 17:12:50 | Accepted | 3579 | 0MS | 316K | 1055 B | G++ | xym2010 |
#include<cstdio> #include<string> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<map> #include<queue> #include<vector> #define LL long long using namespace std; const int size=100005,MAX=1<<30,MIN=-(1<<30); LL m[10],r[10]; void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y) { if(b==0) { x=1,y=0,d=a; } else { ex_gcd(b,a%b,d,y,x); y-=x*(a/b); } } LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b); } LL china_remain(int n) { LL a,b,c,c1,c2,x,y,d,N; a=m[0];c1=r[0]; for(int i=1;i<n;i++) { b=m[i];c2=r[i]; ex_gcd(a,b,d,x,y); c=c2-c1; if(c%d)return -1; LL b1=b/d; x=((c/d*x)%b1+b1)%b1; c1=a*x+c1; a=a*b1; } if(c1==0)//当余数都为0 { c1=1; for(int i=0;i<n;i++) c1=c1*m[i]/gcd(c1,m[i]); } return c1; } int main() { int T,n; scanf("%d",&T); for(int t=1;t<=T;t++) { scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lld",&m[i]); for(int i=0;i<n;i++) scanf("%lld",&r[i]); cout<<"Case "<<t<<": "<<china_remain(n)<<endl; } return 0; }