这题也搞了好久,现在还有点没有全部理解,还请高人指点……
这道题不能用中国剩余定理,因为按照剩余定理的要求,a1,a2,a3....an要两两互素,而此题不符合。
此题的方法是用扩展欧几里德,逐渐合并。
例如有前两对数,a1,r1,a2,r2;
设所求的数为m,则有:a1*x+r1=m=a2*y+r2
联立得:a1*x-a2*y=r2-r1;
设r=r2-r2;
求出gcd(a1,a2)判断是否符合:r%gcd!=0;
不符合就不用往下算了,输出-1;
符合就继续:
设a1*X-a2*Y=gcd;
temp=a2/gcd; //这个就不太理解了
x=(X*r/gcd%temp+temp)%temp; //这个是防止为负数的情况
r1=a1*x+r1; //这个就是a1*x+r1=m
a1=a1*a2/gcd; //这个也不太理解了
此时两个方程就和并成了一个。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; ll gcd(ll a,ll b) { ll t=(!b?a:gcd(b,a%b)); //记忆递归省点时间 return t; } void exgcd(ll a,ll b,ll &x,ll &y) { if(!b) {x=1;y=0;return;} exgcd(b,a%b,y,x); //这里用记忆化递归时间还是一样的,所以不用 y-=a/b*x; } int main() { ll i,k,a1,r1,a2,r2,c,x,y,l,t; while(cin>>k) { int flag=0; cin>>a1>>r1; for(i=1;i<k;i++) { cin>>a2>>r2; if(flag) continue; c=r2-r1; l=gcd(a1,a2); if(c%l!=0) {flag=1;continue;} exgcd(a1,a2,x,y); t=a2/l; x=((c/l*x)%t+t)%t; r1+=a1*x; a1*=t; } if(flag) cout<<-1<<endl; else cout<<r1<<endl; } return 0; }