中国剩余定理
前言
本文介绍了中国剩余定理及其扩展,可以用于求解一元线性同余方程组。
具体来说,它们能解决如下问题:
中国剩余定理(CRT)
CRT 在求解上文提到的问题时有个限制条件,就是 \(\forall 1\le i<j\le n,\gcd(m_i,m_j)=1\),即模数两两互质。
至于为什么会有这个限制我们会在下文解释。
求解过程
我们令 \(\displaystyle m=\operatorname{lcm}(m_1,m_2,\cdots,m_n)=\prod_{i=1}^nm_i\)。
则原方程有一个唯一解 \(x\equiv x_0\pmod m\)。
我们不妨设 \(\displaystyle x_0=\sum_{i=1}^nc_ir_i\)。
若所有都 \(c_i\) 满足
即可满足原式。
即 \(c_i\equiv1\pmod{m_i},\dfrac{m}{m_i}\mid c_i\)。
我们不妨令 \(m_i'=\dfrac{m}{m_i}\),再令 \(c_i=k_im_i'\),就有 \(k_im_i'\equiv1\pmod{m_i}\),所以 \(k_i=m_i'^{-1}\)。
因此,\(c_i=m_i'm_i'^{-1}\)。(注意此处 \(c_i\) 不能对 \(m_i\) 取模)
因此 \(\displaystyle x_0=\sum_{i=1}^nm_i'm_i'^{-1}r_i\)。
顺便证明下 \(x\equiv x_0\pmod{m}\) 是该方程组的唯一解。
证明:
设 \(x_0'\) 也满足所有方程,且 \(x_0'\not\equiv x_0\pmod{m}\)。
显然有 \(x_0'\equiv r_i\equiv x_0\pmod{m_i}\),所以 \(m_i\mid(x_0'-x_0)\)。
即 \(m\mid(x_0'-x_0)\),故 \(x_0'\equiv x_0\pmod{m}\),矛盾。
故 \(x\equiv x_0\pmod{m}\) 是该方程组的唯一解。
上述就是 CRT 的求解方法,下面概括下具体过程:
- 计算 \(\displaystyle m=\prod_{i=1}^nm_i\);
- 对于第 \(i\) 个方程:
-
- 计算 \(m_i'=\dfrac{m}{m_i}\);
-
- 计算 \(m_i'\) 在模 \(m_i\) 意义下的逆元 \(m_i'^{-1}\);
-
- 计算 \(c_i=m_i'm_i'^{-1}\)(不要对 \(m_i\) 取模)。
- 最终方程组在模 \(m\) 意义下的唯一解为 \(\displaystyle x\equiv\sum_{i=1}^nc_ir_i\pmod{m}\)。
实现
int CRT(int n,int *r,int *m){
int M=1,ans=0;
for(int i=0;i<n;++i)M*=m[i];
for(int i=0;i<n;++i){
int m_=M/m[i],invm_,tmp;
exgcd(m_,m[i],invm_,tmp);//m_*invm_ mod m[i] =1
ans=(ans+r[i]*m_*invm_%M)%M;
}
return (ans%M+M)%M;
}
//n 是方程个数,r[] 是余数数组,m[] 是模数数组
//exgcd(a,b,x,y) 用于求解 ax+by=gcd(a,b) 的问题,此处用于求逆元
扩展中国剩余定理(exCRT)
注意到在 CRT 求解时需要计算 \(m_i'\) 关于 \(m_i\) 的逆元,这就要求 \(\gcd(m_i',m_i)=1\)。
但如果模数不满足两两互质呢?这时候 CRT 就不能正常求解了,所以 exCRT 就上场了。
求解过程
考虑最原始的办法:将两个方程合并成一个方程。
考虑如下问题
我们需要给出一个解或判断无解。
把其转化成不定方程形式,则有 \(x=m_1x_1+r_1=m_2x_2+r_2\),即 \(m_1x_1-m_2x_2=r_2-r_1\)。
根据裴蜀定理,当 \(\gcd(m_1,m_2)\not\mid (r_2-r_1)\) 时,原方程无解,否则有解。
若有解,则可以用 exgcd 求出一组可行解 \((x_1,x_2)\),则合并后的方程为 \(x\equiv m_1x_1+r_1\pmod{\operatorname{lcm}(m_1,m_2)}\)。
实现
int exCRT(int n,int *r,int *m){
int r1=r[0],r2,m1=m[0],m2,x1,x2,d;
for(int i=1;i<n;++i){
r2=r[i],m2=m[i];
if((r2-r1)%(d=exgcd(m1,m2,x1,x2))!=0)return -1;
int M=m1*m2/d;
x1*=(r2-r1)/d;
r1=(m1*x1+r1)%M;
m1=M;
}
return (r1%M+M)%M;
}
//exgcd(a,b,x,y) 求解 ax+by=gcd(a,b) 并返回 gcd(a,b)
//当原方程组无解时返回 -1

浙公网安备 33010602011771号