拓展中國剩餘定理(exCRT)
阿新 • • 發佈:2020-09-03
演算法簡介
中國剩餘定理用於求同餘方程組。
理論
我們要解
\[\begin{cases} x≡a_1(mod\quad m_1)\\ x≡a_2(mod\quad m_2)\\ ......\\ x≡a_n(mod\quad m_n) \end{cases} \]
下面是仲爺的個性解法:
考慮合併2個方程
\[ x≡a_1\pmod{m_1}\\ x≡a_2\pmod{m_2} \]
設\(x=a_1+y_1m_1=a_2+y_2m_2\)
新合併的方程便是\(x≡a_1+y_1m_1≡a_2+y_2m_2\pmod {lcm(m1,m2)}\)
於是用exgcd對\(a_1-a_2=y_2m_2-y_1m_1\)
下面是主流解法:
假設知道前\(k-1\)個方程的解\(x\),假設\(m=lcm_{i=1}^{k-1}b_i\),那麼\(x+i*m(i\in Z)\)肯定是前\(k-1\)個方程的通解。於是用exgcd解出\(x+i*m≡a_i\pmod {b_i}\)。
程式碼(沒過,畢竟\(O(1)\)快速乘有精度問題)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5; int n; ll a[N+10],b[N+10]; inline ll Read() { ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)&&ch!='-') ch=getchar(); ch=='-'?f=-1:x=ch-'0'; while(isdigit(ch=getchar())) x=x*10+ch-'0'; return x*f; } ll mul(ll x,ll y,ll md) {return (x*y-(ll)((long double)x/md*y)*md+md)%md;} ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;} ll lcm(ll x,ll y) {return x*y/(gcd(x,y));} void exgcd(ll A,ll B,ll &x,ll &y) { if(!B) {x=1,y=0;return;} exgcd(B,A%B,x,y); ll tmp=x; x=y,y=tmp-(A/B)*y; } inline ll excrt() { ll ans=a[1],m=b[1],x,y; for(register int i=2;i<=n;++i) { ll gc=gcd(m,b[i]),tmp=((a[i]-ans)%b[i]+b[i])%b[i]; exgcd(m,b[i],x,y); x=mul(x,tmp/gc,b[i]); ans+=m*x; m*=b[i]/gc; ans=(ans+m)%m; } return ans; } int main() { n=Read(); for(register int i=1;i<=n;++i) b[i]=Read(),a[i]=Read(); cout<<excrt(); return 0; }