中国剩余定理 (Chinese Remainder Theorem)
CRT是解决下列同余方程问题的, m i , m j m_i,m_j mi,mj两两互质。
该定理只需要用到两个取余知识点:
1. a % b = c → ( a + k b ) % b = c a\%b=c\rightarrow (a+kb)\%b=c a%b=c→(a+kb)%b=c
2. a % b = c → ( k a ) % b = k c ( k c < b ) a\%b=c\rightarrow (ka)\%b=kc\ (kc<b) a%b=c→(ka)%b=kc (kc<b)
该问题当模数两两互质必有解。
令 M i M_i Mi是除了 m i m_i mi之外的所有 m j m_j mj的 l c m = ∏ j = 1 n m [ j ] m [ i ] lcm=\dfrac{\prod\limits_{j=1}^nm[j]}{m[i]} lcm=m[i]j=1∏nm[j]。
令 M i t ≡ 1 ( m o d m i ) M_it\equiv 1\pmod{m_i} Mit≡1(modmi)
⇒ M i t + m i y = 1 \Rightarrow M_it+m_iy=1 ⇒Mit+miy=1
由 e x g c d exgcd exgcd可解出 t t t。
这个满足 x ≡ a i ( m o d m i ) x\equiv a_i\pmod{m_i} x≡ai(modmi)的式子,我们先找到该式余1的解: M i t M_it Mit。
然后由知识 2 2 2可得, a i × M i × t ( m o d m i ) = a i a_i\times M_i\times t\pmod{m_i}=a_i ai×Mi×t(modmi)=ai
最后的答案就是: ∑ i = 1 n a i M i t i ( m o d M ) \sum\limits_{i=1}^n a_iM_it_i\pmod{M} i=1∑naiMiti(modM)
该解是最小正整数解。
代码
void exgcd(ll a,ll b,ll &x,ll &y){
//ax+by=1
if(!b){
x=1,y=0;
return;
}
exgcd(b,a%b,y,x);
y-=(a/b)*x;
}
ll m[N],a[N];//m[i] modulus (relatively prime) a[i] remainder
ll crt(int n){ //Chinese Remainder Theorem (nlogM)
ll M=1;//product of modulus
for(int i=1;i<=n;i++)
scanf("%lld%lld",&m[i],&a[i]),M*=m[i];
ll ans=0;
for(int i=1;i<=n;i++){
ll x,y;
ll u=M/m[i];// Inverse
exgcd(u,m[i],x,y);// ux+m[i]y=1
ans=(ans+1LL*a[i]*u*x%M)%M; //sum of a[i]*u*x
}
return (ans%M+M)%M;//Minimum positve integer
}
扩展中国剩余定理
假设我们已经求出前 i − 1 i-1 i−1个方程的解 x x x,且令 M = l c m { m j } j ∈ [ 1 , i − 1 ] M=lcm\{m_j\} j\in[1,i-1] M=lcm{mj}j∈[1,i−1]
则 x x x的通解为: x + k M x+kM x+kM
对于第 i i i个方程: ( x + k M ) ≡ a i ( m o d m i ) (x+kM)\equiv a_i\pmod{m_i} (x+kM)≡ai(modmi)
即: k M = ( a i − x ) ( m o d m i ) kM=(a_i-x)\pmod{m_i} kM=(ai−x)(modmi)
k M + m i y = ( a i − x ) kM+m_iy=(a_i-x) kM+miy=(ai−x)
由 e x g c d exgcd exgcd可解得: k k k。
所以前 i i i个方程的解 x ′ = x + k M x'=x+kM x′=x+kM,然后更新 M = l c m ( M , m i ) M=lcm(M,m_i) M=lcm(M,mi)进入下个方程即可。
代码
ll exgcd(ll a,ll b,ll &x,ll &y){
//ax+by=1
if(!b){
x=1,y=0;
return a;
}
ll g=exgcd(b,a%b,y,x);
y-=(a/b)*x;
return g;
}
ll qmul(ll a,ll b,ll m){
ll s=0;
while(b){
if(b&1) s=(s+a)%m;
a=(a+a)%m;
b>>=1;
}
return s;
}
ll m[N],a[N];//m[i] modulus (relatively prime) a[i] remainder
ll excrt(int n){ //Chinese Remainder Theorem (nlogM)
ll M=1,ans=0;//product of modulus
for(int i=1;i<=n;i++){
ll x,y,c=(a[i]-ans%m[i]+m[i])%m[i];
ll g=exgcd(M,m[i],x,y);
if(c%g) return -1;//no answer
ll g1=m[i]/g,g2=c/g;
x=qmul(x,g2,g1);
ans+=x*M;
M*=g1;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;//Minimum positve integer
}
Hint
求 { k i x = a i ( m o d m i ) } \{k_ix=a_i\pmod{m_i}\} {kix=ai(modmi)}
类似 e x c r t excrt excrt
已知前 i − 1 i-1 i−1个方程的通解: x + t M x+tM x+tM
则 k i ( x + t M ) = a i ( m o d m i ) k_i(x+tM)=a_i\pmod{m_i} ki(x+tM)=ai(modmi)
( k i M ) t + m i y = a i − k i x (k_iM)t+m_iy=a_i-k_ix (kiM)t+miy=ai−kix
由 e x g c d exgcd exgcd可解得 t t t。
因此可求出 x x x。
记忆方法
上述两个定理的关键都是: m i x + M i y = c m_ix+M_iy=c mix+Miy=c 解出 x x x。
一个是: M i x + m i y = 1 M_ix+m_iy=1 Mix+miy=1
a n s = ∑ a i M i x ( m o d M ) ans=\sum a_iM_ix \pmod{M} ans=∑aiMix(modM)
一个是: M i x + m i y = ( a i − a n s ) M_ix+m_iy=(a_i-ans) Mix+miy=(ai−ans)
a n s = ∑ M i x ( m o d M ) ans=\sum M_ix \pmod{M} ans=∑Mix(modM)
参考文章
具体证明可参考这篇文章