第二十九章 数论——中国剩余定理与线性同余方程组

第二十九章 数论——中国剩余定理与线性同余方程组

  • 一、中国剩余定理
    • 1、作用:
    • 2、内容:
    • 3、证明:
      • (1)逆元的存在性
      • (2)验证定理的正确性
    • 4、代码实现:
      • (1)步骤:
      • (2)问题:
      • (3)代码:

一、中国剩余定理

1、作用:

我们上一章节中,详细地讲解了如何利用扩展欧几里德算法解一个线性同余方程,但是如果我们遇到了线性同余方程组的话,我们就需要用到今天所讲解的中国剩余定理。

但是中国剩余定理的成立前提是,方程组中的模数两两互质。

2、内容:

对于方程组:

{ x ≡ a 1 ( m o d   m 1 ) x ≡ a 2 ( m o d   m 2 ) x ≡ a 3 ( m o d   m 3 ) . . . x ≡ a n ( m o d   m n ) \begin{cases} x\equiv a_1(mod\ m_1)\\ x \equiv a_2(mod \ m_2)\\ x \equiv a_3(mod\ m_3)\\ ...\\ x \equiv a_n(mod\ m_n) \end{cases} xa1(mod m1)xa2(mod m2)xa3(mod m3)...xan(mod mn)
最终的结果

x = ∑ k = 1 n a k c k c k − 1 x=\sum_{k=1}^{n}a_kc_kc_k^{-1} x=k=1nakckck1

其中:

M = ∏ k = 1 n m k M=\prod_{k=1}^{n}m_k M=k=1nmk
c k = M m k c_k=\frac{M}{m_k} ck=mkM
c k − 1 c_k^{-1} ck1是模数为 m k m_k mk的时候, c k c_k ck的逆元。

3、证明:

(1)逆元的存在性

我们先证明一下,逆元 c k − 1 c_k^{-1} ck1是存在的。

因为 m m m之间是互质的,而 c k c_k ck中不含有 m k m_k mk。因此, g c d ( c k , m k ) = 1 gcd(c_k,m_k)=1 gcd(ck,mk)=1

裴蜀定理可知:

存在 x c k + y m k = 1 xc_k+ym_k=1 xck+ymk=1

即: x c k = − y m k + 1 xc_k=-ym_k+1 xck=ymk+1

即: x c k ≡ 1 ( m o d   m k ) xc_k\equiv1(mod\ m_k) xck1(mod mk)

此时的 x x x就是逆元 c k − 1 c_k^{-1} ck1,所以逆元必定是存在的。

(2)验证定理的正确性

假设一个 c i c_i ci

i   = = k i \ ==k i ==k的时候,

c i ∗ c i − 1 ≡ 1 m o d ( m k ) c_i*c_i^{-1}\equiv 1 mod(m_k) cici11mod(mk)

两侧同时乘 a i a_i ai

a i c i ∗ c i − 1 ≡ a i   m o d ( m k ) a_ic_i*c_i^{-1}\equiv a_i\ mod(m_k) aicici1ai mod(mk)

i   ! = k i \ !=k i !=k的时候,

此时的 c i c_i ci当中是存在 m k m_k mk的,不存在的是 m i m_i mi

由于 c i c_i ci包含了 m k m_k mk,所以此时 c i ∣ m k c_i|m_k cimk

c i % m k = 0 c_i\%m_k=0 ci%mk=0

两边同时乘以 a i c i − 1 a_ic_i^{-1} aici1还是 0 0 0

因此,综合上述两种情况:
我们的 x % m k = 0 + 0 + . . . + a k c k c k − 1 + 0 x\%m_k=0+0+...+a_kc_kc_k^{-1}+0 x%mk=0+0+...+akckck1+0

即:

x ≡ a k c k c k − 1 m o d ( m k ) x\equiv a_kc_kc_k^{-1}mod(m_k) xakckck1mod(mk)

因为在第一种情况下,我们得到了:

a k c k ∗ c k − 1 ≡ a k   m o d ( m k ) a_kc_k*c_k^{-1}\equiv a_k\ mod(m_k) akckck1ak mod(mk)

所以:

x ≡ a k m o d ( m k ) x\equiv a_kmod(m_k) xakmod(mk)

符合我们的方程组。因此这个结论是正确的。

4、代码实现:

(1)步骤:

第一步:计算 M M M

第二步:计算 c i c_i ci

第三步:计算 c i − 1 c_i^{-1} ci1(利用扩展欧几里德算法)

这里讲解一下如何计算逆元 c i − 1 c_i^{-1} ci1

c i ∗ c i − 1 ≡ 1 ( m o d   m i ) c_i*c_i^{-1}\equiv 1(mod\ m_i) cici11(mod mi)

即:

c i c i − 1 + y m i = 1 c_ic_i^{-1}+ym_i=1 cici1+ymi=1

这个式子中,我们不知道的未知数有两个,一个是 c i − 1 c_i^{-1} ci1,另一个是 y y y

但我们知道的是: c i , m i c_i,m_i ci,mi

所以我们可以用扩展欧几里德算法+裴蜀定理

计算出 x ∗ c i + y ∗ m i = g c d ( c i , m i ) x*c_i+y*m_i=gcd(c_i,m_i) xci+ymi=gcd(ci,mi)

g c d ( c i , m i ) = 1 gcd(c_i,m_i)=1 gcd(ci,mi)=1

所以,我们用这两个式子求的就是,我们的目标变量
c i − 1 c_i^{-1} ci1 y y y

也就是说,我们的 x = c i − 1 x=c_i^{-1} x=ci1

第四步:套用中国剩余定理

(2)问题:

洛谷:中国剩余定理模板题
第二十九章 数论——中国剩余定理与线性同余方程组_第1张图片

(3)代码:

#include
using namespace std;
typedef long long LL;
const int N=1e5+10;
int n;
LL m[N],a[N];
//扩展欧几里德算法
LL exgcd(LL a,LL b,LL&x,LL&y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    else
    {
        LL res=exgcd(b,a%b,x,y);
        LL tmp=y;
        y=x-a/b*y;
        x=tmp;
        return res;
    }
}
//中国剩余定理
LL CRT(LL m[],LL a[])
{
    LL M=1,ans=0;
    //计算M
    for(int i=1;i<=n;i++)M*=m[i];
    for(int i=1;i<=n;i++)
    {
    	//得到ci
        LL c=M/m[i],x,y;
        //计算逆元
        exgcd(c,m[i],x,y);
        //利用中国剩余定理公式
        ans=(ans%M+a[i]*c*x%M)%M;
    }
    //返回答案
    return (ans%M+M)%M;
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&m[i],&a[i]);
    }
    cout<<CRT(m,a)<<endl;
    return 0;
}

你可能感兴趣的:(算法合集,算法)