中国剩余定理 学习笔记

中国剩余定理

中国剩余定理(Chinese remainder theorem, CRT)可以求解如下形式的同余方程组:

\[\left\{\begin{matrix}x\equiv b_1\pmod{a_1} \\x\equiv b_2\pmod{a_2} \\\vdots\\x\equiv b_n\pmod{a_n}\end{matrix}\right. \]

首先构造几个同余方程组 \(\left\{\begin{matrix}x\equiv 1\pmod{a_1}\\x\equiv 0\pmod{a_2}\\\vdots\\x\equiv0\pmod{a_n}\end{matrix}\right.,\left\{\begin{matrix}x\equiv 0\pmod{a_1}\\x\equiv 1\pmod{a_2}\\\vdots\\x\equiv0\pmod{a_n}\end{matrix}\right.,\dots,\left\{\begin{matrix}x\equiv 0\pmod{a_1}\\x\equiv 0\pmod{a_2}\\\vdots\\x\equiv 1\pmod{a_n}\end{matrix}\right.\)

求解这些方程组,以 \(\left\{\begin{matrix}x\equiv 1\pmod{a_1}\\x\equiv 0\pmod{a_2}\\\vdots\\x\equiv0\pmod{a_n}\end{matrix}\right.\) 为例:

\(m=\prod_{i=1}^{n}a_i,m_i=\frac{m}{a_i}\)。显然 \(\prod_{i=2}^{n}a_i=\frac{m}{a_1}=m_1\) 满足第一个方程以外的所有方程。求出 \(m_1\)\(a_1\) 的逆元 \(m_1^{-1}\),根据逆元的定义有 \(m_1m_1^{-1}\equiv1\pmod{a_1}\),因此 \(m_1m_1^{-1}\) 为一个解。

将这些方程组分别乘上 \(b_1,b_2\dots b_n\),得到 \(\left\{\begin{matrix}x\equiv b_1\pmod{a_1}\\x\equiv 0\pmod{a_2}\\\vdots\\x\equiv0\pmod{a_n}\end{matrix}\right.,\left\{\begin{matrix}x\equiv 0\pmod{a_1}\\x\equiv b_2\pmod{a_2}\\\vdots\\x\equiv0\pmod{a_n}\end{matrix}\right.,\dots,\left\{\begin{matrix}x\equiv 0\pmod{a_1}\\x\equiv 0\pmod{a_2}\\\vdots\\x\equiv b_n\pmod{a_n}\end{matrix}\right.\) 发现将这些方程组求和,刚好得到原方程,因此求和即为最终的解。

总结一下流程:

  1. \(m=\prod_{i=1}^{n}a_i\)

  2. \(m_i=\frac{m}{a_i}\)

  3. \(m_i\)\(a_i\) 的逆元 \(m_i^{-1}\)

  4. 对于每一个方程,重复2、3,最终的解为 \(\sum_{i=1}^n b_im_im_i^{-1}\)

由于最小解不会超过 \(m\),所以要处处对 \(m\) 取模。

template<typename T>T crt(int n,T a[],T b[]){
  T m=1,ans=0;
  for(int i=1;i<=n;i++)m*=a[i];
  for(int i=1;i<=n;i++)ans=(ans+b[i]*(m/a[i])%m*inv(m/a[i],a[i])%m)%m;
  return ans;
}

然而在第三步,逆元可能不存在,即 \(a\) 不是两两互质。这时需要扩展中国剩余定理。

扩展中国剩余定理

假如现有两个同余方程 \(x\equiv b_1\pmod{a_1},x\equiv b_2\pmod{a_2}\),等价于 \(x=a_1k_1+b_1=a_2k_2+b_2\)

移项得到 \(a_1k_1-a_2k_2=b_2-b_1\)。这是一个形如 \(ax+by=c\) 的二元一次方程,可以使用扩展欧几里得算法求解。

首先当 \(\gcd(a_1,a_2)\nmid b_2-b_1\) 时判定无解。否则用扩欧求 \(a_1k_1-a_2k_2=\gcd(a_1,a_2)\)\(k_1\) 的特解 \(x_1\),有 \(k_1=\frac{x_1(b_2-b_1)}{\gcd(a_1,a_2)}\)。对 \(k_1\)\(\frac{a_2}{\gcd(a_1,a_2)}\)\(k_2\)\(\frac{a_1}{\gcd(a_1,a_2)}\) 也是一组解,可以对 \(\frac{a_2}{\gcd(a_1,a_2)}\) 取模。

此时可以求出 \(x\),那么可以将两个同余方程合并成一个新的方程 \(x\equiv b_3\pmod{a_3}\)。其中 \(a_3=\operatorname{lcm}(a_1,a_2), b_3=x\)。整个算法的过程就是不断合并方程,最终成为一个方程,得到的 \(b\) 就是解。

template<typename T>T excrt(int n,T a[],T b[]){
  T a1=a[1],b1=b[1];
  for(int i=2;i<=n;i++){
    T c=b[i]-b1,x,y,d=gcd(a1,a[i]);
    exgcd(a1,a[i],x,y);
    if(c%d==0)x=(x%(a[i]/d)*(c/d)%(a[i]/d)+a[i]/d)%(a[i]/d),b1+=x*a1,a1*=a[i]/d;
    else return -1;
  }
  return b1;
}

[[数学]]

posted @ 2024-03-01 09:35  lgh_2009  阅读(24)  评论(0)    收藏  举报