扩展中国剩余定理

题意: 给定 n n n个整数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an n n n个整数 m 1 , m 2 , . . . m n m_1,m_2,...m_n m1,m2,...mn ∀ i ∈ [ 1 , n ] , x ≡ m i ( m o d a i ) \forall i\in[1,n],x\equiv m_i\pmod {a_i} i[1,n],xmi(modai)。求存在的最小 x x x
题解:
依次合并每个同余式。
下面以两个同余式为例:
x ≡ m 1 ( m o d a 1 ) x\equiv m_1\pmod {a_1} xm1(moda1)
x ≡ m 2 ( m o d a 2 ) x\equiv m_2\pmod {a_2} xm2(moda2)

等价于:
x = a 1 k 1 + m 1 x=a_1k_1+m_1 x=a1k1+m1
x = a 2 k 2 + m 2 x=a_2k_2+m_2 x=a2k2+m2

联立可得:
a 1 k 1 + m 1 = a 2 k 2 + m 2 a_1k_1+m_1=a_2k_2+m_2 a1k1+m1=a2k2+m2

移项得:
a 1 k 1 − a 2 k 2 = m 2 − m 1 a_1k_1-a_2k_2=m_2-m_1 a1k1a2k2=m2m1

可以看出来是 e x g c d exgcd exgcd的标准形式,故有解的条件是 g c d ( a 1 , a 2 ) ∣ ( m 2 − m 1 ) gcd(a_1,a_2)\mid(m_2-m_1) gcd(a1,a2)(m2m1)
目标为消去不定因素 k 1 , k 2 k_1,k_2 k1,k2

d = g c d ( a 1 , a 2 ) d=gcd(a1,a2) d=gcd(a1,a2)
两边同除 d d d得:
a 1 d k 1 − a 2 d k 2 = m 2 − m 1 d \frac{a_1}{d}k_1-\frac{a_2}{d}k_2=\frac{m_2-m_1}{d} da1k1da2k2=dm2m1

等价于:
a 1 d k 1 ≡ m 2 − m 1 d ( m o d a 2 d ) \frac{a_1}{d}k_1\equiv \frac{m_2-m_1}{d}\pmod {\frac{a_2}{d}} da1k1dm2m1(modda2)

到这里我们已经消除了 k 2 k_2 k2,继续消除 k 1 k_1 k1即可
对同余式两边同除 a 1 d \frac{a_1}{d} da1,得:
k 1 ≡ i n v ( a 1 d , a 2 d ) × m 2 − m 1 d ( m o d a 2 d ) k_1\equiv inv(\frac{a_1}{d},\frac{a_2}{d})\times\frac{m_2-m_1}{d}\pmod{\frac{a_2}{d}} k1inv(da1,da2)×dm2m1(modda2)
其中 i n v ( a , b ) inv(a,b) inv(a,b)表示 a a a在模 b b b意义下的逆元
k 1 k_1 k1用①式替换,得:
x − m 1 a 1 ≡ i n v ( a 1 d , a 2 d ) × m 2 − m 1 d ( m o d a 2 d ) \frac{x-m_1}{a_1}\equiv inv(\frac{a_1}{d},\frac{a_2}{d})\times\frac{m_2-m_1}{d}\pmod{\frac{a_2}{d}} a1xm1inv(da1,da2)×dm2m1(modda2)
等价于:
x ≡ i n v ( a 1 d , a 2 d ) × m 2 − m 1 d × a 1 + m 1 ( m o d a 1 a 2 d ) x\equiv inv(\frac{a_1}{d},\frac{a_2}{d})\times\frac{m_2-m_1}{d}\times a_1+m_1\pmod{\frac{a_1a_2}{d}} xinv(da1,da2)×dm2m1×a1+m1(modda1a2)
至此, x x x已经变成了完全由已知的 a 1 , a 2 , m 1 , m 2 a_1,a_2,m_1,m_2 a1,a2,m1,m2所表达的同余式了。
形式与 x ≡ m ( m o d a ) x\equiv m\pmod{a} xm(moda)相同
那么合并后的 m = i n v ( a 1 d , a 2 d ) × m 2 − m 1 d × a 1 + m 1 m=inv(\frac{a_1}{d},\frac{a_2}{d})\times\frac{m_2-m_1}{d}\times a_1+m_1 m=inv(da1,da2)×dm2m1×a1+m1 a = l c m ( a 1 , a 2 ) a=lcm(a_1,a_2) a=lcm(a1,a2)
其中 i n v ( a 1 d , a 2 d ) × m 2 − m 1 d inv(\frac{a_1}{d},\frac{a_2}{d})\times\frac{m_2-m_1}{d} inv(da1,da2)×dm2m1相当于求解 a 1 k 1 − a 2 k 2 = m 2 − m 1 a_1k_1-a_2k_2=m_2-m_1 a1k1a2k2=m2m1得到的最小非负 k 1 k_1 k1

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;
int n;

ll exgcd(ll a, ll b, ll &x, ll &y) {
    if(!b) {
        x = 1, y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;   
}

ll gcd(ll a, ll b) {return b == 0 ? a : gcd(b, a % b);}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}

int main()
{
    scanf("%d", &n);
    
    int flag = 1;
    ll a1, m1;
    for(int i = 1; i <= n; i++) {
        if(i == 1) scanf("%lld%lld", &a1, &m1);
        else {
            ll a2, m2;
            scanf("%lld%lld", &a2, &m2);
            ll k1, k2;
            ll d = exgcd(a1, a2, k1, k2); //求出两个mod的gcd
            //判断是否有解
            if((m2 - m1) % d) flag = 0;
            else {
                k1 *= (m2 - m1) / d; //扩大(m2-m1)/d倍
                ll t = a2 / d;//求出模:a2/d
                k1 = (k1 % t + t) % t;//求出最小的非负k1
                
                m1 = a1 * k1 + m1;//合并后的m
                a1 = abs(a1 / d * a2);//合并后的a
            }
        }
    }
    if(flag) printf("%lld\n", (m1 % a1 + a1) % a1);
    else puts("-1");
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值