中国剩余定理及其扩展

中国剩余定理


m 1 , m 2 , m 3 ⋯ m n m_1,m_2,m_3\cdots m_n m1,m2,m3mn两两互素,有同余方程组:

{ x ≡ a 1   ( m o d   m 1 ) x ≡ a 2   ( m o d   m 2 ) ⋯ x ≡ a n   ( m o d   m n ) \begin{cases} x \equiv a_1\ ({\rm mod}\ m_1) \\ x\equiv a_2\ ({\rm mod}\ m_2) \\ \cdots \\ x \equiv a_n\ ({\rm mod}\ m_n)\end{cases} xa1 (mod m1)xa2 (mod m2)xan (mod mn)
求最小的满足方程的 x x x


由于网上对中国剩余定理的基本概念讲述的差不多了,这里就直接给简单证明。


为了方便后面的描述,我们定义 M = ∏ i = 1 n m i   ,   w i = M m i M=\prod\limits_{i=1}^nm_i\ ,\ w_i=\frac{M}{m_i} M=i=1nmi , wi=miM(这个定义不用于后面的扩展中国剩余定理和其它情况)。

我们的目的是想对于每一个方程找出一个比较特殊的 p i p_i pi,使得 p i ≡ a i   m o d   m i p_i\equiv a_i\ {\rm mod}\ m_i piai mod mi,且 p i ≡ 0   m o d   m j ( j ≠ i ) p_i\equiv 0\ {\rm mod}\ m_j(j≠i) pi0 mod mj(j=i),因为求出所有的 p i p_i pi后, ∑ i = 1 n p i   m o d   M \sum\limits_{i=1}^np_i\ {\rm mod}\ M i=1npi mod M就是我们的答案 x x x

观察 p i p_i pi的限制,可以发现 p i p_i pi应该为除了 m i m_i mi以外的模数的最小公倍数(因为所有 m i m_i mi互质,所以也就是 w i w_i wi)的倍数,所以我们只需找到一个 p i p_i pi使得 p i = k i w i p_i=k_iw_i pi=kiwi k i k_i ki为任意整数),且 p i ≡ a i   m o d   m i p_i\equiv a_i\ {\rm mod}\ m_i piai mod mi,那么这个 p i p_i pi就是我们需要的。但是 p i ≡ a i   m o d   m i p_i\equiv a_i\ {\rm mod}\ m_i piai mod mi这个式子并不特殊,我们需要找一些更方便求解的式子来替换它。思考一下可以发现,其实我们只需要找到在满足 p i = k i w i p_i=k_iw_i pi=kiwi的条件下,使得 p i ≡ 1   m o d   m i p_i \equiv 1\ {\rm mod}\ m_i pi1 mod mi的数,把 p i p_i pi乘上 a i a_i ai,就得到我们想要的 p i p_i pi

现在的问题就是如何找到满足条件的 k i k_i ki,观察式子 k i w i ≡ 1   m o d   m i k_iw_i\equiv 1\ {\rm mod}\ m_i kiwi1 mod mi,可以看到 k i k_i ki实际上是 w i w_i wi在模 m i m_i mi意义下的逆元,所以: p i = a i × w i × k i = a i × w i × w i − 1 p_i=a_i×w_i×k_i=a_i×w_i×w_i^{-1} pi=ai×wi×ki=ai×wi×wi1

到这里,我们就成功得出了中国剩余定理的公式:
x ≡ ∑ i = 1 k a i × w i × w i − 1 ( m o d   M ) x\equiv \sum_{i=1}^ka_i×w_i×w_i^{-1}({\rm mod}\ M) xi=1kai×wi×wi1(mod M)

扩展中国剩余定理


由于一般情况下模数并不是两两互素,那么之前的做法就行不通了,所以我们就需要用到扩展中国剩余定理。

我们将上面的同余方程组更改一下:
{ x = p 1 m 1 + a 1 x = p 2 m 2 + a 2 ⋯ x = p n m n + a n \begin{cases}x=p_1m_1+a_1 \\ x=p_2m_2+a_2 \\ \cdots \\x=p_nm_n+a_n\end{cases} x=p1m1+a1x=p2m2+a2x=pnmn+an

对于这种形式,比较好的办法就是两两合并成一个方程。以合并前两个方程为例:

根据等式可得: m 1 p 1 + a 1 = m 2 p 2 + a 2 m_1p_1+a_1=m_2p_2+a_2 m1p1+a1=m2p2+a2

移项: m 1 p 1 − m 2 p 2 = a 2 − a 1 m_1p_1-m_2p_2=a_2-a_1 m1p1m2p2=a2a1

由于 p 2 p_2 p2可正可负,为了方便推导,我们变一下号: m 1 p 1 + m 2 p 2 = a 2 − a 1 m_1p_1+m_2p_2=a_2-a_1 m1p1+m2p2=a2a1

根据贝祖定理可以知道,若 g c d ( m 1 , m 2 ) ∤ a 2 − a 1 gcd(m_1,m_2)\nmid a_2-a_1 gcd(m1,m2)a2a1,那么整个同余方程无解。

在有解的情况下则可用扩展欧几里得求出一组 x , y x,y x,y使得: m 1 x + m 2 y = g c d ( m 1 , m 2 ) m_1x+m_2y=gcd(m_1,m_2) m1x+m2y=gcd(m1,m2)

两边同时乘上 a 2 − a 1 g c d ( m 1 , m 2 ) \frac{a_2-a_1}{gcd(m_1,m_2)} gcd(m1,m2)a2a1: m 1 x ( a 2 − a 1 ) g c d ( m 1 , m 2 ) + m 2 y ( a 2 − a 1 ) g c d ( m 1 , m 2 ) = a 2 − a 1 m_1\frac{x(a_2-a_1)}{gcd(m_1,m_2)}+m_2\frac{y(a_2-a_1)}{gcd(m_1,m_2)}=a_2-a_1 m1gcd(m1,m2)x(a2a1)+m2gcd(m1,m2)y(a2a1)=a2a1

根据多项式恒等定理: p 1 = x ( a 2 − a 1 ) g c d ( m 1 , m 2 ) , p 2 = y ( a 2 − a 1 ) g c d ( m 1 , m 2 ) p_1=\frac{x(a_2-a_1)}{gcd(m_1,m_2)},p_2=\frac{y(a_2-a_1)}{gcd(m_1,m_2)} p1=gcd(m1,m2)x(a2a1),p2=gcd(m1,m2)y(a2a1)

那么: m 1 p 1 + a 1 = a 2 − m 2 p 2 = x m_1p_1+a_1=a_2-m_2p_2=x m1p1+a1=a2m2p2=x
所以我们目前得到了满足前两个方程的一个 x x x的解,
合并后的同余方程为: x ≡ m 1 p 1 + a 1   m o d   l c m ( m 1 , m 2 ) x \equiv m_1p_1+a_1\ {\rm mod}\ {\rm lcm}(m_1,m_2) xm1p1+a1 mod lcm(m1,m2)

或者也可以是:

x ≡ a 2 − m 2 p 2   m o d   l c m ( m 1 , m 2 ) x \equiv a_2-m_2p_2\ {\rm mod}\ {\rm lcm}(m_1,m_2) xa2m2p2 mod lcm(m1,m2)

若我们要得到满足所有方程的解,那么我们只要把合并后的方程再与其它的方程合并,最后剩下的一个方程就是答案。

应用:【模板】扩展中国剩余定理

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N=100010;
int n;
LL x,y,lcm,equ[N][2];
LL multi(LL a,LL b,LL p)
{
    a=(a%p+p)%p;b=(b%p+p)%p;LL ans=0;
    for(;a;a>>=1,b=(b*2)%p)if(a&1)ans=(ans+b)%p;
    return ans;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    LL val=exgcd(b,a%b,x,y);
    LL t=x;x=y;y=t-a/b*y;return val;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
     scanf("%lld%lld",&equ[i][1],&equ[i][0]);
    for(int i=1;i<n;i++)
    {
        LL val=exgcd(equ[i][1],equ[i+1][1],x,y);
        lcm=equ[i][1]/val*equ[i+1][1];
        equ[i+1][1]=lcm;
        val=multi(x,(equ[i+1][0]-equ[i][0])/val,lcm);
        equ[i+1][0]=(multi(equ[i][1],val,lcm)+equ[i][0])%lcm;
    }
    printf("%lld\n",(equ[n][0]%equ[n][1]+equ[n][1])%equ[n][1]);
    return 0;
}

注意乘法溢出

其它情况

{ w 1 x ≡ a 1   ( m o d   m 1 ) w 2 x ≡ a 2   ( m o d   m 2 ) ⋯ w k x ≡ a k   ( m o d   m k ) \begin{cases} w_1x \equiv a_1\ ({mod}\ m_1) \\ w_2x\equiv a_2\ ({mod}\ m_2) \\ \cdots \\ w_kx \equiv a_k\ ({mod}\ m_k)\end{cases} w1xa1 (mod m1)w2xa2 (mod m2)wkxak (mod mk)

若未知数 x x x的系数不为 1 1 1,当 w i w_i wi m i m_i mi互质时可以用 e x g c d exgcd exgcd求出逆元将 w i w_i wi除到另一边,但是如果不互质又该怎么办?我们尝试能不能将其转换成互质的形式。

若要使得 w i w_i wi m i m_i mi互质,我们则需要对方程两边同时除上一个 g c d ( w i , m i ) {\rm gcd}(w_i,m_i) gcd(wi,mi),但是这样的正确性和更改后的方程又如何?

Q i = g c d ( w i , m i ) Q_i={\rm gcd}(w_i,m_i) Qi=gcd(wi,mi),那么 w i = Q i l i , m i = Q i r i w_i=Q_il_i,m_i=Q_ir_i wi=Qili,mi=Qiri。将方程转化为以下形式:

Q i l i × x = a i + Q i r i × q i Q_il_i×x=a_i+Q_ir_i×q_i Qili×x=ai+Qiri×qi

其中 q i q_i qi为任意整数,那么 a i = Q i ( l i × x + r i × q i ) a_i=Q_i(l_i×x+r_i×q_i) ai=Qi(li×x+ri×qi),也就是说 a i a_i ai必为 Q i Q_i Qi的倍数,若不满足的话则方程组无解,否则我们可以将方程两边同时除以 Q i Q_i Qi得到以下形式:

l i × x = a i ′ + r i × q i l_i×x=a_i'+r_i×q_i li×x=ai+ri×qi

可以发现 l i x ≡ a i ′   m o d   r i ⇔ w i x ≡ a i   m o d   m i l_ix\equiv a_i'\ {\rm mod}\ r_i\Leftrightarrow w_ix\equiv a_i\ {\rm mod}\ m_i lixai mod riwixai mod mi

那么我们可以将原方程替换为 l i x ≡ a i ′   m o d   r i l_ix\equiv a_i'\ {\rm mod}\ r_i lixai mod ri,因为 l i , r i l_i,r_i li,ri互质,所以我们就可以用逆元将 l i l_i li除到方程右边,然后就可以用 e x C R T exCRT exCRT求解了。

应用:[NOI2018]屠龙勇士

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值