中国剩余定理 && 扩展中国剩余定理

本文详细介绍了中国剩余定理的基本概念及其应用,包括求解同余方程组的方法,并提供了扩展中国剩余定理的实现代码及示例。适用于数学算法竞赛及计算机科学领域的学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中国剩余定理

问题

求解同余方程组
{ 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 k ( m o d    m k ) \begin{cases} x\equiv\ a_1(\mod m_1) \quad \\ x\equiv\ a_2(\mod m_2) \quad \\ x\equiv\ a_3(\mod m_3) \quad \\ ...\quad \\ x\equiv\ a_k(\mod m_k) \quad \\ \end{cases} x a1(modm1)x a2(modm2)x a3(modm3)...x ak(modmk)
其中 m 1 , m 2 , m 3 . . . m k m_1,m_2,m_3...m_k m1,m2,m3...mk两两互质的整数
求x的最小非负整数解

定理

M = ∏ i = 1 k m i M=\prod_{i=1}^km_i M=i=1kmi,即M是所有 m i m_i mi的最小公倍数

t i t_i ti为同余方程 M m i t i ≡   1 ( m o d    m i ) \frac{M}{m_i}t_i \equiv\ 1(\mod m_i) miMti 1(modmi)的最小非负整数解

则有一个解为 x = ∑ i = 1 k a i M m i t i x=\sum_{i=1}^ka_i\frac{M}{m_i}t_i x=i=1kaimiMti

通解为 x + i ∗ M ( i ∈ Z ) x+i*M(i\in Z) x+iM(iZ)
特别的,最小非负整数解为 ( x (x (x% M + M ) M+M) M+M)% M M M

证明

因为 M m i \frac{M}{m_i} miM是除 m i m_i mi之外的所有m的倍数
所以 ∀ k ≠ i , a i M m i t i ≡ 0 ( m o d    m k ) \forall k \not= i, a_i\frac{M}{m_i}t_i \equiv 0(\mod m_k) k=i,aimiMti0(modmk)
又有 M m i t i ≡   1 ( m o d    m i ) \frac{M}{m_i}t_i \equiv\ 1(\mod m_i) miMti 1(modmi)
两边同时乘 a i a_i ai a i M m i t i ≡ a i ( m o d    m i ) a_i\frac{M}{m_i}t_i \equiv a_i(\mod m_i) aimiMtiai(modmi)
带入 x = ∑ i = 1 k a i M m i t i x=\sum_{i=1}^ka_i\frac{M}{m_i}t_i x=i=1kaimiMti
原方程组成立
——算法竞赛进阶指南

代码实现

t i t_i ti同余式的求解可以用扩展欧几里得

void exgcd(int a,int b,int &x,int &y)
{
    if(b==0){ x=1; y=0; return;}
    exgcd(b,a%b,x,y);
    int tp=x;
    x=y; y=tp-a/b*y;
}

int china()
{
    int ans=0,lcm=1,x,y;
    for(int i=1;i<=k;++i) lcm*=b[i];
    for(int i=1;i<=k;++i)
    {
        int tp=lcm/b[i];
        exgcd(tp,b[i],x,y);
        x=(x%b[i]+b[i])%b[i];//x要为最小非负整数解
        ans=(ans+tp*x*a[i])%lcm;
    }
    return (ans+lcm)%lcm;
}

一道模板题

洛谷P3868 [TJOI2009]猜数字 题解

扩展中国剩余定理

问题

求解同余方程组
{ 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 k ( m o d    m k ) \begin{cases} x\equiv\ a_1(\mod m_1) \quad \\ x\equiv\ a_2(\mod m_2) \quad \\ x\equiv\ a_3(\mod m_3) \quad \\ ...\quad \\ x\equiv\ a_k(\mod m_k) \quad \\ \end{cases} x a1(modm1)x a2(modm2)x a3(modm3)...x ak(modmk)
其中 m 1 , m 2 , m 3 . . . m k m_1,m_2,m_3...m_k m1,m2,m3...mk不一定两两互质的整数
求x的最小非负整数解

模板题 洛谷P4777 【模板】扩展中国剩余定理(EXCRT)

求解

假设已经求出前k-1个方程组成的同余方程组的一个解为x
且有 M = L C M i − 1 k − 1 m i M=LCM_{i-1}^{k-1}m_i M=LCMi1k1mi
则前k-1个方程的方程组通解为 x + i ∗ M ( i ∈ Z ) x+i*M(i\in Z) x+iM(iZ)

那么对于加入第k个方程后的方程组
我们就是要求一个正整数t,使得
x + t ∗ M ≡ a k ( m o d    m k ) x+t*M \equiv a_k(\mod m_k) x+tMak(modmk)

转化一下上述式子得
t ∗ M ≡ a k − x ( m o d    m k ) t*M \equiv a_k-x(\mod m_k) tMakx(modmk)

对于这个式子我们已经可以通过扩展欧几里得求解t
若该同余式无解,则整个方程组无解
若有,则前k个同余式组成的方程组的一个解解为 x k = x + t ∗ M x_k=x+t*M xk=x+tM

所以整个算法的思路就是求解k次扩展欧几里得

lt exgcd(lt a,lt b,lt &x,lt &y)
{
    if(b==0){x=1;y=0;return a;}
    lt gcd=exgcd(b,a%b,x,y);
    lt tp=x;
    x=y; y=tp-a/b*y;
    return gcd;
}

lt excrt()
{
    lt x,y,k;
    lt M=bi[1],ans=ai[1];//第一个方程的解特判
    for(int i=2;i<=n;i++)
    {
        lt a=M,b=bi[i],c=(ai[i]-ans%b+b)%b;//ax≡c(mod b)
        lt gcd=exgcd(a,b,x,y),bg=b/gcd;
        if(c%gcd!=0) return -1; //判断是否无解
        
        x=mul(x,c/gcd,bg);
        ans+=x*M;//更新前k个方程组的答案
        M*=bg;//M为前k个m的lcm
        ans=(ans%M+M)%M;
    }
    return (ans%M+M)%M;
}

update

针对一些对代码的疑问做点解答

Q:c=(ai[i]-ans%b+b)%b是什么意思

我们推导出 t ∗ M ≡ a k − x ( m o d    m k ) t*M \equiv a_k-x(\mod m_k) tMakx(modmk)
其中 a k − x a_k-x akx对应 a x ≡ c ( m o d    b ) ax≡c(\mod b) axc(modb)中的c,这句代码里 a n s ans ans对应 x x x b b b对应 m k m_k mk
所以这句话就是把 a k − x a_k-x akx先对 m k m_k mk取模

Q:为啥不加个括号变成c=((ai[i]-ans)%b+b)%b

ans%b的范围是[0,b-1),a[i]-ans%b+b一定不会小于0的,当然加了也没问题

Q:为什么 M ∗ = b g M*=bg M=bg而不是 M ∗ = b M*=b M=b

这里bg=b/gcd(a,b)对应到推到部分公式里的就是 b g = m k / g c d ( m k , L C M i = 1 k − 1 m i ) bg=m_k/gcd(m_k,LCM_{i=1}^{k-1}m_i) bg=mk/gcd(mk,LCMi=1k1mi)
M ∗ = b g M*=bg M=bg明显就是令M为前k个m的最小公倍数

Q:这句话x=mul(x,c/gcd,bg)为什么要乘c/gcd,为什么模数是bg

建议复习扩展欧几里得

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值