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

中国剩余定理

问题

求解同余方程组
{ 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的最小非负整数解

求解

假设已经求出前k-1个方程组成的同余方程组的一个解为x
且有 M = l c m ( ∏ i − 1 k − 1 m i ) M=lcm(\prod_{i-1}^{k-1}m_i) M=lcm(i1k1mi)
则前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;
}

一道模板题

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

相关推荐
©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页