对于一个同余方程
对于第一个和第二个式子
则有:
ans=a1+k1∗n1
ans=a2+k2∗n2
就有:
a1+k1∗n1=a2+k2∗n2
k1∗n1−k2∗n2=a2−a1
故我们设c=a2−a1 再变化一下形式就有:
k1∗n1+(−k2)∗n2=c
令 gcd=gcd(n1,n2)
这样我们就可以通过exgcd来求出一组解x1,y1
满足 x1∗n1+y2∗n2=gcd
故:x1∗d/g∗n1+y2∗d/g∗n2=g∗c/gcd
则: k1=x1∗c/gcd,k2=y1∗c/gcd
从而得到一组通解((k1+q)*n1+(k2-p)*n2=c)
k1=k1+q=k1+n2/gcd∗T
k2=k2-p=k2−n1/gcd∗T
要使所求得的解最小且为正整数则可以根据 k1 的通解形式求得
mink1=(k1%(n2/gcd)+n2/gcd)%(n2/gcd)
再带入ans=a1+mink1∗n1 得到 ans
令 A 为合并后的 a , N 为合并后的 n
所以N=lcm(n1,n2)=n1∗n2/gcd
根据ans≡A (mod N) 且 ans 是满足该式子最小的值
得到: A=ans
代码
#include<bits/stdc++.h> using namespace std; #define ll __int128 ll ans,a[100010],n[100010],N,a1,a2,n1,n2,c,gcd,x,y; long long read() { ll f=1,x=0; char ss=getchar(); while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();} while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();} return f*x; } void exgcd(ll aa,ll bb,ll &gcd,ll &x,ll &y) { if(!bb) { gcd=aa; x=1,y=0; return; } exgcd(bb,aa%bb,gcd,x,y); ll tr=x; x=y; y=tr-aa/bb*y; } long long zs() { a1=a[1],n1=n[1]; for(ll i=2;i<=N;i++) { a2=a[i],n2=n[i]; c=a2-a1; exgcd(n1,n2,gcd,x,y);//n1*x+n2*y=gcd(n1,n2)的解 if(c%gcd==0) { ll k1=x*c/gcd;//n1*k1+n2*k2=c的解 ll mink1=(k1%(n2/gcd)+(n2/gcd))%(n2/gcd);//k1通解:k1=k1+(n2/gcd)*t ans=mink1*n1+a1;//这2个方程的解 //合并2个方程 n1=(n1*n2)/gcd; a1=ans; } else return -1; } return ans; } int main() { N=read(); for(ll i=1;i<=N;i++) n[i]=read(),a[i]=read(); cout<<zs(); return 0; }