zoukankan      html  css  js  c++  java
  • 中国剩余定理(CRT / EXCRT)

    中国剩余定理(CRT)

    (洛谷 曹冲养猪)题目链接

    中国剩余定理是用于求解诸如:

    $ $ $ $ $ $ $ $

    形式的同余方程组的定理。其中 (m_1, m_2 ... m_k)两两互质的整数。

    解法

    设:

    [M = prod^{n}_{i = 1}m_i , M_i = frac{M}{m_i} , t_iM_i equiv 1 (\% m_i) ]

    统计答案:

    [ans = sum_{i=1}^{n} a_iM_it_i ]

    栗子

    今有物不知其数,三三数之剩二(除以三余二),五五数之剩三(除以五余三),七七数之剩二(除以七余二)。问物几何?

    根据刚才的算法来解决此问题:

    (1.)(3)(5) 的公倍数中找到被 (7) 除余 (1) 的最小数 (15),从 (3)(7) 的公倍数中找出被 (5) 除余 (1) 的最小数 (21),从 (5)(7) 的公倍数中找出被 (3) 除余 (1) 的最小数 (70)

    (2.)(15) 乘以 (2)(除以 (7) 的余数),(21) 乘以 (3)(除以 (5) 的余数),(70) 乘以 (2)(除以 (3) 的余数)。三个乘积相加得到 (15 * 2 + 21 * 3 + 70 * 2 = 233)

    (3.)(233) 除以 (3, 5, 7) 三个数的最小公倍数 (105),得到的余数 (23) 就是该问题的答案。

    因为不会证明,在这里放上大佬的证明: 1. 2.

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define LL long long
    using namespace std;
    
    const int N = 233333;
    LL n, x, y, ans = 0, Mul = 1, a[N], m[N], M[N], inv[N];
    
    void exgcd(LL a, LL b)
    {
        if(b == 0) { x = 1, y = 0; return ; }
        exgcd(b, a % b);
        LL tx = x;
        x = y, y = tx - (a / b) * y;
    }
    
    int main()
    {
        scanf("%lld", &n);
        for(int i = 1; i <= n; i++)
            scanf("%lld%lld", &m[i], &a[i]), Mul *= m[i];
        for(int i = 1; i <= n; i++)
        {
            M[i] = Mul / m[i];
            exgcd(M[i], m[i]);
            x = (x % m[i] + m[i]) % m[i];
            ans += x * a[i] * M[i];
        }
        printf("%lld", ans % Mul);
        return 0;
    }
    

    扩展中国剩余定理(EXCRT)

    (洛谷 模板)题目链接

    照抄参考题解

    扩展中国剩余定理是用于求解诸如:

    $ $ $ $ $ $ $ $

    形式的同余方程组的定理。其中 (m_1, m_2 ... m_k)不一定两两互质的整数。

    解法

    假设已经求出前 (k-1) 个方程组成的同余方程组的解为 (x),且有

    [M = prod^{k-1}_{i=1}m_i ]

    (其实这里的连乘不是连乘,而是取这些数的最小公倍数)

    则前 (k-1) 个方程的通解为 (x+iM)(i) 是整数)

    考虑加入第 (k) 个方程:我们需要求一个正整数 (t),使得

    [x+tM equiv a_k (\% m_k) ]

    [⇒tM equiv a_k-x (\% m_k) ]

    转化后的该式右边可以看做常数,因此能使用 exgcd 求解。若对于某一个 (k),该方程无解,则这组数据无解。

    注意做乘法时可能会爆,需要“龟速乘”。

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define LL long long
    using namespace std;
    
    const int N = 2333333;
    LL n, x, y, M = 1, ans = 0, m[N], a[N];
    
    LL gcd(LL x1, LL y1) { y1 == 0 ? x1 : gcd(y1, x1 % y1); }
    
    void exgcd(LL a, LL b)
    {
        if(b == 0) { x = 1, y = 0; return ; }
        exgcd(b, a % b);
        LL tx = x;
        x = y, y = tx - (a / b) * y;
    }
    
    LL mul(LL a, LL b, LL mod)
    {
        LL res = 0;
        while(b)
        {
            if(b & 1) res = (res + a) % mod;
            a = (a + a) % mod;
            b >>= 1;
        }
        return res;
    }
    
    int main()
    {
        scanf("%lld", &n);
        for(int i = 1; i <= n; i++) scanf("%lld%lld", &m[i], &a[i]);
        for(int i = 1; i <= n; i++)
        {
            x = y = 0;
            LL A = M, B = m[i], C = ((a[i] - ans) % B + B) % B;
            exgcd(A, B);
            LL Gcd = gcd(A, B), bg = B / Gcd;
            x = mul(x, C / Gcd, bg);
            ans = ans + x * M;
            M *= bg;
            ans = (ans % M + M) % M;
        }
        printf("%lld", (ans % M + M) % M);
        return 0;
    }
    
  • 相关阅读:
    杭电dp题集,附链接还有解题报告!!!!!
    js正則表達式语法
    java界面编程(8) ------ 组合框(下拉列表)
    四个好看的CSS样式表格
    搜集朋友写的几篇Android Elf相关的文档
    hadoop编程小技巧(5)---自己定义输入文件格式类InputFormat
    递归算法
    ua识别(浏览器标识识别)
    amazeui学习笔记一(开始使用5)--藏品collections
    amazeui学习笔记一(开始使用4)--Web App 相关
  • 原文地址:https://www.cnblogs.com/Andy-park/p/13748807.html
Copyright © 2011-2022 走看看