TZOJ 曹冲养猪 (扩展)中国剩余定理

求解:

\equiv a1 (b1)

\equiv a2 (b2)

\equiv a3 (b3)

........

对于 上述式子我们可以拆成 :

M = b1 * p + a1 = b2 * q + a2

左右移项得到:

b1 * p - b2 * q = a2 - a1

可以发现 这就是一个同余方程:

a = b1 , b = b2 , x = p , y = q , c = a2 - a1

 我们就可以用扩展欧几里得算法得到:

p 与 q 的特解 x , y。

同时 p 与 q 的通解也可以获得:p = x + (k * b)  / gcd(a,b) ,q = y + (k * a) / gcd(a,b)

得到新的同余方程:

M = b1 * ( x + k * b / gcd(a,b)) + a1

将原来的  a = b1 , b = b2 , x = p , y = q , c = a2 - a1 。替换回来:

M = b1 * ( p + k * b2 / gcd(b1,b2) ) + a1

化简:因为:b1 * b2 /gcd(b1,b2) =lcm(b1,b2)

所以:M = k * lcm(b1,b2) + p * b1 + a1

得到:新的 a3 =  p * b1 + a1 ,b3 = lcm(b1,b2) 。

这样合并 n - 1次即为答案。

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define int long long
const int N=5e4+100;
namespace crt{
    int bi[N],ai[N]; //ai==a ,bi=m1;
    int n;
    int mul(int a, int b ,int p)
    {
        a%=p,b%=p;
        int z = (long double) a / p * b;
        int res = (unsigned long long) a * b - (unsigned long long) z * p;
        return (res + p) % p;
    }
    int exgcd(int a, int b, int &x, int &y) {
        if(b == 0){
            x = 1; y = 0;
            return a;
        }
        int d = exgcd(b, a % b, x, y);
        int z = x;x = y;y = z - (a / b) * x;
        return d;
    }
    int excrt()//拓展中国剩余定理
    {
        int x, y, k;
        int M = bi[1], ans = ai[1];//第一个方程的特解
        for(int i = 2; i <= n; ++ i) {
            int a = M, b = bi[i], c = (ai[i] - ans % b + b) % b;
            int d = exgcd(a, b, x, y);
            int bg = b / d;//lcm
            if(c % d != 0) return 1e18; //判断是否无解,然而这题其实不用
            x = mul(x, c / d, bg);//快速乘模板
            ans += x * M;//更新前k个方程组的答案
            M *= bg;//M为前k个m的lcm
            ans = (ans % M + M) % M;
        }
        ans = (ans % M + M) % M;
        //if(ans == 0) ans = M;//视情况而定,等于0的时候是因为给定的模数均为1,此时答案应该取任意值均可,而不是只有解 0 ,有时需要特判一下。
        return ans;
    }
};
void solve() {
    int n;
    cin >> n;
    crt::n = n;
    for (int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        crt::bi[i] = x;
        crt::ai[i] = y;
    }
    cout << crt::excrt() << '\n';
}
signed main() {
    IOS;
    int t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值