中国剩余定理
解决同余方程组的相关问题,然而貌似扩展一下发生质变?
同余方程组问题
\[x\equiv a_1 \mod m_1 \]
\[x\equiv a_2 \mod m_2 \]
\[\dots\dots\]
\[x\equiv a_n \mod m_n \]
求解满足上述同余方程组的\(x\)
中国剩余定理(CRT)
- 要求:模数\(m_1,m_2,\dots,m_n\) 必须互质(为什么呢?)
- CRT告诉我们,这个方程组在模\(M=m_1*m_2*\dots*m_n\) 意义下的解是唯一的。
- CRT还告诉我们这个解为\[x\equiv a_1 M_1 M_1^{-1}+a_2 M_2M_2^{-1}+\dots+a_n M_nM_n^{-1} \mod M\]其中\(M_i=M/m_i\) ,而\(M_i^{-1}\) 是模\(m_i\) 意义下的逆元。
- \[x=\sum a_i\frac{M}{m_i}inv(\frac{M}{m_i},\,m_i)\]
- 这个解是构造性的解,可以验证其是满足上述方程组的。
- 为什么两两互质?逆元的要求!
const int maxn=1000;
int a[maxn];
int m[maxn];
int CRT(int n){
int M=1;
int ans=0;
for(int i=1;i<=n;i++){
M*=m[i];
}
for(int i=1;i<=n;i++){
int x,y;
int Mi=M/m[i];
exgcd(Mi,m[i],x,y);
ans=(ans+a[i]*Mi*x)%M;
}
if(ans<0)ans+=M;
return ans;
}
扩展中国剩余定理(exCRT)
- 模数\(m_1,m_2,\dots,m_n\) 不互质的时候也可以有解啦!
- 考虑一下同余方程组仅有两个方程的情况。
- \[x\equiv c_1 \mod m_1 \] ,\[x\equiv c_2 \mod m_2\]
- \[x=c_1 +m_1k_1$ ,$x=c_2 +m_2k_2\]
- \[c_1 +m_1k_1=c_2 +m_2k_2\]
- \[m_1k_1 =c_2-c_1+m_2k_2\]
- 这个方程有解的充要条件是\[\gcd(m_1,m_2)\,|\,(c_2-c_1)\]
- \[\frac{m_1k_1}{\gcd(m_1,m_2)} =\frac{c_2-c_1}{\gcd(m_1,m_2)}+\frac{m_2k_2}{\gcd(m_1,m_2)}\]
- \[\frac{m_1k_1}{\gcd(m_1,m_2)} \equiv\frac{c_2-c_1}{\gcd(m_1,m_2)}\mod \frac{m_2}{\gcd(m_1,m_2)}\]
- \[k_1\equiv inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}\mod \frac{m_2}{\gcd(m_1,m_2)}\]
- \(inv(a,b)\) 表示\(a\) 在模\(b\) 意义下的逆元
- \[k_1=inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}+K* \frac{m_2}{\gcd(m_1,m_2)}\]
- 带回\(x=c_1 +m_1k_1\)
- \[x=c_1 +m_1*(inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}+K* \frac{m_2}{\gcd(m_1,m_2)})\]
- \[x\equiv c_1 +m_1*inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}\mod \frac{m_1m_2}{\gcd(m_1,m_2)}\]
- 到这里,我们已经完成了两个同余方程的整合!有形式\(x\equiv a \mod m\)
- 其中\[a=c_1 +m_1*inv(\frac{m_1}{\gcd(m_1,m_2)},\frac{m_2}{\gcd(m_1,m_2)})*\frac{c_2-c_1}{\gcd(m_1,m_2)}\] \[m=\frac{m_1m_2}{\gcd(m_1,m_2)}\]
- 反复重复以上操作!(二合一,加一,合一,······)
const int maxn=1000;
int a[maxn];
int m[maxn];
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
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 tmp=x;
x=y;
y=tmp-a/b*y;
return d;
}
int inv(int a,int mod){
int x,y;
int d=exgcd(a,mod,x,y);
return d==1?(x%mod+mod)%mod:-1;
}
int exCRT(int n){
int m1, m2, c1, c2, d;
for(int i=2;i<=n;i++){
m1=m[i-1];//这里是与前一个进行合并
m2=m[i];
c1=a[i-1];
c2=a[i];
d=gcd(m1,m2);
if((c2-c1)%d!=0){
return -1;//无法合并
}
m[i]=m[i-1]*m[i]/d;//公式(倒数第二个)
a[i]=c1+m1*inv(m1/d,m2/d)%(m2/d)*(c2-c1)/d;//公式(倒数第二个)
a[i]=(a[i]%m[i]+m[i])%m[i];
}
return a[n];
}