求解同余方程组
x的最小非负整数解。
与普通的中国剩余定理不同的地方在于,这次没有要求(mi,mj)=1.
结论:
如果不满足m两两互质,我们采用合并同余方程的方法将方程两两合并
考虑两个方程:
x≡c1modm1
x
≡
c
1
mod
m
1
x≡c2modm2
x
≡
c
2
mod
m
2
那么我们有
x=m1t1+c1=m2t2+c2
x
=
m
1
t
1
+
c
1
=
m
2
t
2
+
c
2
t1m1−t2m2=c2−c1
t
1
m
1
−
t
2
m
2
=
c
2
−
c
1
,可以看做一个不定方程,用exgcd求解t1的最小非负数解。设g=gcd(m1,m2),则有g|c2-c1,否则无解。exgcd(m1,m2,t1,t2)后,t1*(c2-c1)/g就是t1.t1的通解为
t1+k∗m2/g
t
1
+
k
∗
m
2
/
g
。我们搞出最小正整数的解即可。将t1代回,我们就得到了一个新的方程:
x≡cmodm,c=m1∗t1+c1,m=m1∗m2/g
x
≡
c
mod
m
,
c
=
m
1
∗
t
1
+
c
1
,
m
=
m
1
∗
m
2
/
g
。
最终的c就是答案。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 15
inline ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n;
inline ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1;y=0;return a;}
ll res=exgcd(b,a%b,x,y);ll t=x;x=y;y=t-a/b*y;return res;
}
int main(){
// freopen("a.in","r",stdin);
while(~scanf("%d",&n)){
bool flag=0;ll m1=read(),a1=read();--n;
while(n--){
ll m2=read(),a2=read(),t1,t2;
if(flag) continue;
ll g=exgcd(m1,m2,t1,t2);
if((a2-a1)%g){flag=1;continue;}
t1*=(a2-a1)/g;m2/=g;t1=(t1%m2+m2)%m2;
a1+=t1*m1;m1*=m2;a1%=m1;
}if(flag) puts("-1");
else printf("%lld\n",a1);
}return 0;
}