http://poj.org/problem?id=2891
题目大意:
k个不同的正整数a1,a2,...,ak。对于一些非负m,满足除以每个ai(1≤i≤k)得到余数ri。求出最小的m。
输入和输出中的所有整数都是非负数,可以用64位整数类型表示。
——————————————
首先我们打眼一看可能是孙子定理。
但是我们无法保证a一定互质。
那么显然就要用我们的可爱的exgcd啦!
(下面题解根据这位大佬所懂http://blog.csdn.net/zmh964685331/article/details/50527894)
显然对于x=r(mod a)
我们有:
x+y1a1=r1①
x-y2a2=r2②
x-y3a3=r3③
……
①②相减得:
y1a1+y2a2=r1-r2
我们就有了标准的exgcd的方程了。
不能解就是-1
否则我们能求出其中一个y1,将其化为最小值后,带入①得到
x0=r1-y1a1
这是x的其中一个解,全解为
x=x0+k*lcm(a1,a2)
即
x=x0(mod lcm(a1,a2))
则:
x+y3*lcm(a1,a2)=x0④
③④再联立,重复以上过程即可。
#include<cstdio> #include<iostream> #include<cstring> #include<cctype> using namespace std; typedef long long ll; inline ll read(){ ll X=0,w=0; char ch=0; while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } ll exgcd(ll a,ll b,ll &x,ll &y){ if(b==0){ x=1;y=0; return a; } ll r=exgcd(b,a%b,x,y); ll temp; temp=x; x=y; y=temp-(a/b)*y; return r; } ll a[100001],r[100001]; int main(){ int k; while(scanf("%d",&k)!=EOF){ bool ok=0; for(int i=1;i<=k;i++){ a[i]=read(); r[i]=read(); } ll a1=a[1],r1=r[1]; for(int i=2;i<=k;i++){ ll A=a1,B=a[i],C=r1-r[i]; ll x,y; ll g=exgcd(A,B,x,y); if(C%g){ printf("-1\n"); ok=1; break; } x=C/g*x%a[i]; r1=r1-x*a1; a1=a1*a[i]/g; } if(ok)continue; printf("%lld\n",(r1%a1+a1)%a1); } return 0; }