暑假acwing算法总结22:中国剩余定理

  • 中国剩余定理

求最小的x满足线性同余方程组
x 同余 a1(mod m1)
x 同余 a2(mod m2)
……
x 同余 an(mod mn)
(题中m1,m2……mn两两互质)

  • 证明:

  • 先讨论前两个线性同余方程组

  • x=k1 ∗ \ast m1+a1,x=k2 ∗ \ast m2+a2

  • 只要满足存在k1,k2使得(m1,m2) | a2 - a1就一定有解,设该最大公因数为d

  • 有性质:(k1,k2的解系)

  • k1=k1+k ∗ m2 ÷ \div ÷ d

  • k2=k2+k ∗ m1 ÷ \div ÷ d

  • (k为任意整数k1,k2仍满足关系)

  • 证明:

  • 将新的k1,k2带入式子得:

  • (k1+k ∗ m2 ÷ \div ÷ d) ∗ m1 + (k2+k ∗ m1 ÷ \div ÷ d) ∗ (-m2)

  • 化简后上式等于a2 - a1故证出

  • 要找一个最小的非负整数解,我们只需要让

  • k1=k1 mod abs (m2 ÷ \div ÷ d)

  • k2=k2 mod abs (m1 ÷ \div ÷ d)

  • 即可找到当前最小的k1,k2的解,即此时的k=0

  • 新的x为:

  • x=(k1+k ∗ m2 ÷ \div ÷ d) ∗ m1+a1

  • x=k1 ∗ m1+a1 + k ∗ lcm(m1,m2)

  • 这里,k都为0了,为什么还要算呢

  • 因为这只是前两个式子得最小k,有可能遇到下一个式子后面被迫扩大

  • a0=lcm(m1,m2),m0=k1∗m1+a1

  • 那么:x=k∗m0+a0

  • 这个形式与一开始我们分解的形式是不是特别像呢?

  • 没错!假设之后又来了一个a3,m3

  • 我们只需要继续找:

  • x=k∗m0+a0=k3∗(−m3)+a3,那么问题又回到了第一步

  • 我们的做法相当于每次考虑合并两个式子,将这n个式子合并n−1次后变为一个式子。最后剩下的式子就满足我们的答案。

  • 代码实现

#include<iostream>

using namespace std;

typedef long long LL;//数据范围比较大,所以用LL来存储

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;
}

int main()
{
    int n;
    LL a1,m1;
    cin>>n>>a1>>m1;
    LL x=0;
    for(int i=1;i<n;i++)
    {
        LL a2,m2;
        cin>>a2>>m2;
        LL k1,k2;
        LL d=exgcd(a1,a2,k1,k2);
        if((m2-m1)%d)
        {
            x=-1;
            break;
        }
        k1*=(m2-m1)/d;
        //因为此时k1是k1*a1+k2*a2=d的解,所以要乘上(m2-m1)/d的倍数大小
        LL t=abs(a2/d);
        k1=(k1%t+t)%t;
        //数据比较极端,所以只求k的最小正整数解
        m1=k1*a1+m1;
        //m1在被赋值之后的值为当前"x"的值,此时赋值是为了方便下一轮的继续使用
        a1=abs(a1*a2/d);
        //循环结束时a1的值为当前所有的a1,a2,……an中的最小公倍数
    }
    if(x!=-1)
    x=(m1%a1+a1)%a1;
    //当循环结束时,此时的值应该与最小公倍数取模,以求得最小正整数解
    printf("%lld\n",x);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值