洛谷 p4777 扩展中国剩余定理(excrt)
前置知识:扩展欧几里得、裴蜀定理、求解线性同余方程;
题意:解同余方程组 模数不互质...
解线性同余方程用exgcd 比如解 ax≡c(mod b)
也就是 ax+by=c,
exgcd可以解出 ax+by=gcd(a,b) ,
方程同乘一个c/gcd(a,b)也就是 a*(x*c/gcd)+b(y*c/gcd)=c
所以exgcd解出x再乘一个c/gcd(a,b)就是一组可行解
解同余方程组 已知前i-1项通解 x0+k*LCM k∈Z ,
引入第i项时 求出一个最小的t满足 x0+t*LCM ≡ ai(mod mi) 此时x=x0+t*LCM 就是答案....
怎么解这个方程?移下向 t*LCM ≡ ai-x0(mod mi),满足ax≡c(mod b) exgcd解就行了
有些题还要用裴蜀定理判无解 这道不用 看代码...
// 已知前i-1项通解 x0+k*LCM k∈Z //引入第i项时 求出一个最小的t满足 x0+t*LCM ≡ ai(mod mi) 此时x=x0+t*LCM // 移向 t*LCM ≡ ai-x0 (mod mi) // 扩欧 求 即可 // ax≡c(mod b) exgcd算出 ax≡1(mod b) x再乘上c/gcd(a,b)即可 c%gcd(a,b)!=0时无解 #include<bits/stdc++.h> #define int long long using namespace std; typedef long long lt; int x,y; int n,ai[100000],bi[100000]; int mul(int a,int b, int p){ int res=0; while(b){ if(b&1){ res=(res+a)%p; } a=(a+a)%p; b>>=1; } return res; }//龟速乘 int exgcd(int a,int b,int &x,int &y){ if(b==0){ x=1; y=0; return a; } int d=exgcd(b,a%b,x,y); int t=x; x=y; y=t-(a/b)*y; return d; }//扩欧 int excrt(){ int ans=ai[1],LCM=bi[1]; for(int i=2;i<=n;i++){ int a=LCM,b=bi[i],c=(ai[i]-ans%b+b)%b;//a ≡c(mod b) int gcd=exgcd(a,b,x,y),bg=b/gcd;//算t*LCM ≡ gcd(mod mi) if(c%gcd!=0)return -1;//无解情况 x=mul(x,c/gcd,bg);//t*LCM ≡ ai-x0 (mod mi) 先算 t*LCM ≡ gcd (mod mi) 答案再乘上 (ai-x0)/gcd即为t // 为什么要模b/gcd呢 我们知道 x=x0+t*LCM 写成同余方程即为 x ≡ x0(mod LCM)所以%LCM对答案没影响 //但是 直接%当前的LCM可能会炸 所以我们一层一层模 我们知道LCM1=LCM0*(b1/gcd), //LCM0再上一层已经模过了(即x中已经过滤掉LCM0的倍数了) 我们只需要再模完(b1/gcd)就可以了 就相当于模LCM1了 ans+=x*LCM; //答案 LCM*=bg;//更新LCM ans=(ans%LCM+LCM)%LCM; } return (ans%LCM+LCM)%LCM; }//扩展中国剩余定理 signed main(){ scanf("%lld",&n); for(int i=1;i<=n;i++){ scanf("%lld%lld",&bi[i],&ai[i]); } printf("%lld",excrt()); }