题目大意:
求解一元线性同余方程组:
x≡b1(mod
m1)
x≡b2(mod
m2)
……
x≡bn(mod
mn)
若无解输出-1,否则输出最小正整数解。
解题思路:
考虑只有两个方程:
x≡b1(mod
m1)
x≡b2(mod
m2)
设
(m1,m2)=d
可以转化为:
x=m1y1+b1
x=m2y2+b2
联立移项得
m2y2+m1y1(y1正负无所谓)=b1−b2
这时我们就可以用拓展欧几里得把最小的
y2
求出,而我们知道
y2+m1dt,t∈Z
都是该方程的解,所以得到:
x=m2(y2+m1dt)+b2=m2y2+b2+m1m2dt
。
我们取特解 x1=m2y2+b2 ,所以 x=x1+m1m2dt
这时假设有第三个方程:
x≡b3(mod
m3)
那么同理:
x=m3y3+b3=x1+m1m2dt
移项得:
m3y3+m1m2dt=x1−b3
,
可以发现这与
m2y2+m1y1=b1−b2
同构,所以迭代求解即可。
由 x=x1+m1m2dt 可知最小正整数解在 [1,m1m2d] 之间,取模即可。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<vector>
#include<set>
#define ll long long
using namespace std;
int n;
ll b1,b2,m1,m2,d;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
b?(exgcd(b,a%b,y,x),y-=a/b*x):(x=1,y=0);
}
ll solve()
{
ll x,y,a=m2,b=m1,c=b1-b2;
d=gcd(a,b);
if(c%d!=0)return -1;
a/=d,b/=d,c/=d;
exgcd(a,b,x,y);
x*=c;x=(x%b+b)%b;
return x;
}
int main()
{
//freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
ll y2;
while(scanf("%d",&n)!=EOF)
{
y2=0;
scanf("%lld%lld",&m1,&b1);
for(int i=2;i<=n;i++)
{
scanf("%lld%lld",&m2,&b2);
if(y2==-1)continue;
y2=solve();
m1=m1*(m2/d);b1=(b2+m2*y2)%m1;
}
if(y2==-1)puts("-1");
else cout<<b1<<'\n';
}
return 0;
}