Introduction
给定 \(n\) 组关于 \(x\) 的一元线性同余方程组:
\[\begin{cases} {x \equiv a_1 \pmod{m_{1}}} \\ {x \equiv a_2 \pmod{m_{2}}} \\ \vdots \\ {x \equiv a_n \pmod{m_{n}}} \end{cases} \]
其中对于 \(\forall i,j \in [1,n] \text{ and } i \ne j\) 满足 \(\gcd(m_i,m_j) = 1\) 。
求其最小非负整数解。
Chinese Remainder Theorem
令 \(M = \prod_{i=1}^n m_i , M(i) = \frac{M}{m_i} , t_i\) 为方程 \(M(i) \times t_i \equiv 1 \pmod{m_i}\) 的一个解。
那么上述方程组的解为
\[x = \sum\limits_{i=1}^n a_i t_i M(i) \]
但这只是一个解,如果要求最小整数解呢?很简单,只要将 \(x\) 对 \(M\) 取模即可。
Code
模板题:Luogu P1495 【模板】中国剩余定理(CRT)/曹冲养猪
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
typedef long long ll;
void exgcd(ll a,ll b,ll &c,ll &x,ll &y){
if(!b){c=a,x=1ll,y=0ll;return;}
exgcd(b,a%b,c,y,x),y-=x*(a/b);
}
ll inv(const ll &b,const ll &p){
ll c,x,y; exgcd(b,p,c,x,y);
return c==1ll?(x+p)%p:-1ll;
}
const int N=12;
int m[N],a[N],n;
int t[N];
ll M=1ll;
signed main() {
cin>>n;
for(register int i=1;i<=n;i++) {
cin>>m[i]>>a[i];
M*=m[i];
}
for(register int i=1;i<=n;i++)
t[i]=inv(M/m[i],m[i]);
ll ans=0ll;
for(register int i=1;i<=n;i++)
ans+=a[i]*(M/m[i])*t[i];
cout<<(ans+M)%M<<endl;
return 0;
}
Proof
为什么这个解是可行的?
由 \(M(i)\) 的定义可知:
\(\forall i \in [1,n] , \begin{cases} {a_i t_i M(i) \equiv 0 \pmod{m_j}} & i\ne j \\ {a_i t_i M(i) \equiv a_i \pmod{m_j}} & i=j \end{cases}\)
显然, \(x = \sum_{i=1}^n a_i t_i M(i)\) 就是方程的解。
为什么只需对 \(M\) 取模就能得到最小整数解?
设 \(x\) 就是上述得到的特殊解。
那么,由于 \(m_{1\cdots n}\) 两两互质,因此方程组的解集可表示为:
\[\{ x + kM | k \in \mathbf{Z} \} \]
因此,在 \([0,M)\) 范围内只存在唯一解,而且同时是最小非负整数解。那么将得到的特殊解对 \(M\) 取模即可。