• X问题 中国剩余定理


    X问题

    X问题
    求在小于等于N的正整数中有多少个X满足:

    X mod a[0] = b[0], 
    X mod a[1] = b[1], 
    X mod a[2] = b[2],
    …, 
    X mod a[i] = b[i],
    … 
    (0 < a[i] <= 10)。
    

    思路

    跟[[中国剩余定理#模板 | 中国剩余定理]]一样的结构, 那么就转化一下:
    x = k1*a[0] + b[0]
    x = k2 * a[1] + b[1]
    先看前两个式子如何合并:
    k1*a[0] + b[0] = k2 * a[1] + b[1]
    移项得:
    k1 * a[0] - k2 * a[1] = b[1] - b[0]
    因为正负无所谓, 所以这里直接把 a[1] 变成负数
    k1 * a[0] + k2 * a[1] = b[1] - b[0]
    通过扩展欧几里得定理得出 k1, k2 的值, 然后化为通解
    k1 = k1 + k*(a[1] / d)
    k2 = k2 + k*(a[0] / d)
    带入x中得:
    x = (k1 + k * a[1] / d)*a[0] + b[0]
    x = k * (a[1] / d) * a[0] + k1*a[0] + b[0]
    故合并后x的式子中:
    a 为 k * (a[1] / d) * a[0]
    b 为 k1 * a[0] +b[0]
    则更新时这样更新:

    b1 = k1 * a1 + b1;
    a1 = abs((a1 / d) * a[i]); // a1 一般比 a[i] 大, 故防溢出先除 a1
    

    最后的答案 x = b1 + k*a1
    其中 b1 就是最小的x, 求在N之下有多少个x成立, 则将 k 变成1, 2, 3 ... 直到 x 超出n即可。

    根据扩展欧几里得定理可得, 当 b[1] - b[0] 无法被 gcd(a1, a[i]) 整除时, 无法合并, 无解。

    代码

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    inline int readInt()
    {
        int t;
        scanf("%d", &t);
        return t;
    }
    template <typename T>
    inline T exgcd(T a, T b, T &x, T &y)
    {
        if (!b)
        {
            x = 1, y = 0;
            return a;
        }
        T t = exgcd(b, a % b, y, x);
        y -= a / b * x;
        return t;
    }
    //------- Coding Area ---------//
    const int N = 1e2 + 10, MOD = 100003;
    // int f[N][N];
    long long n, m;
    long long a[12], b[12];
    int main()
    {
        int T;
        cin >> T;
        while (T--)
        {
            cin >> n >> m;
            for(int i = 0; i < m; i++) a[i] = readInt();
            for(int i = 0; i < m; i++) b[i] = readInt();
            long long a1 = a[0], b1 = b[0], k1, k2;
            bool flag = true;
            for(int i = 1; i < m; i++)
            {
                long long d = exgcd(a1, -a[i], k1, k2);
                if ((b[i] - b1) % d)
                    flag = false;
                // 这里是优化为最小整数解, 提高速度
                k1 *= (b[i] - b1) / d;
                long long t = a[i] / d;
                k1 = (k1 % t + t) % t;
                
                b1 = k1 * a1 + b1;
                a1 = abs((a1 / d) * a[i]);
            }
            if (flag && b1 <= n)
            {
                b1 = (b1 % a1 + a1) % a1;
                long long res = (n - b1) / a1; // 这是除去 最小非负整数x 之后的其他解
                if (b1 != 0) // 若 x 不为0则算一个解
                    res++;
                cout << res << endl;
            }
            else
                cout << 0 << endl;
        }
        return 0;
    }
    
  • 相关阅读:
    通过数据库查看EBS的登录地址
    重启redis报错:Waiting for Redis to shutdown
    Tomcat8启动报there was insufficient free space available after evicting expired cache entries
    EBS安装过程报错,oracle.apps.fnd.txk.config.ProcessStateException: FileSys OS COMMAND Failed : Exit=2 See log for details.
    CentOS系统将UTC时间修改为CST时间
    Tomcat启动时报错,Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext
    LICEcap 录制Gif动画
    Java 8 Optional In Depth
    IntelliJ IDEA推荐插件
    Java 8 – Convert Map to LIST
  • 原文地址:https://www.cnblogs.com/edwinaze/p/16474287.html
Copyright © 2020-2023  润新知