扩展中国剩余定理,是求解形如:
$x\equiv a_{1}($ mod $b_{1})$
$x\equiv a_{2}($ mod $b_{2})$
$x\equiv a_{3}($ mod $b_{3})$
$x\equiv a_{i}($ mod $b_{i})$
...
$x$ 的解(最小非负整数解)
考虑只有一个等式,显然,$x$ 的解可以为 $a_{i}$,而$x+t*b_{i}$ 可以表示出 $x$ 的所有解。
考虑我们已经得到一个解 $x$,和一个可以构造出通解的参数 $M$,将该解与下一个方程进行合并,则不难得出等式:$x+y*M=a_{j}+k*b_{j}$,
进行小小的转化,得:
$M*y+b_{j}*(-k)=a_{j}-x$.
这里有一个小问题,就是等式的右边可能是负数,显然这就非常不好办。
好在 $a_{j'}$ 可以由 $a_{j}$ 加上若干个 $b_{j}$ 得到,所以我们将右边进行一下变换:
$(a_{j}-x$ % $b_{j}+b_{j})$ % $b_{j}$.
用 $exgcd$ 求出 $y$ 的值后,可以 $x$ 的新解就是 $x+y*M$.
这时 $M'=M*\frac{b_{j}}{gcd(b_{j},M)}$,至于为什么,由于笔者实力有限,并不知道如何证明这一步。
Code:
#include<iostream>
#include<string>
#include<cstdio>
typedef long long ll;
using namespace std;
void setIO(string a){ freopen((a+".in").c_str(),"r",stdin), freopen((a+".out").c_str(),"w",stdout);}
const int maxn=100000+5;
int n;
ll ai[maxn],bi[maxn];
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0){ x=1, y=0; return a;}
ll gcd=exgcd(b,a%b,x,y);
ll tp=x;
x=y, y=tp-a/b*y;
return gcd;
}
ll mult(ll a,ll b,ll mod){
long long res=0;
while(b>0){
if(b&1) res=(res+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return res;
}
ll excrt(){
ll x,y;
ll ans=bi[1],M=ai[1];
for(int i=2;i<=n;++i){
ll a=M,b=ai[i],c=(bi[i]-ans%ai[i]+ai[i])%ai[i];
ll gcd=exgcd(a,b,x,y);
x=mult(x,c/gcd,b/gcd);
ans+=x*M;
M*=b/gcd;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i)
cin>>ai[i]>>bi[i];
cout<<excrt();
}