zoukankan      html  css  js  c++  java
  • 中国剩余定理&Lucas定理&按位与——hdu 5446

    链接:

    hdu 5446

    http://acm.hdu.edu.cn/showproblem.php?pid=5446

    题意:

    给你三个数$n, m, k$

    第二行是$k$个数,$p_1,p_2,p_3 cdots p_k$

    所有$p$的值不相同且p都是质数

    求$C(n, m) \%  (p_1*p_2*p_3* cdots *p_k)$的值

    范围:$1leq mleq nleq 1e18, 1leq kleq 10,p_ileq 1e5$保证$p_1*p_2*p_3* cdots *p_k leq 1e18$

    分析:

    我们知道题目要求$C(n, m) \% (p_1*p_2*p_3* cdots *p_k)$的值

    其实这个就是中国剩余定理最后算出结果后的最后一步求余

    那$C(n, m)$相当于以前我们需要用中国剩余定理求的值

    然而$C(n, m)$太大,我们只好先算出$C(n,m) \% p_1 = r_1 \ C(n,m) \% p_2 = r_2 \ C(n,m) \% ; p_3 = r_3 \ vdots \ C(n,m) \% p_k = r_k \$

    用$Lucas$,这些$r_1,r_2,r_3 cdots r_k$可以算出来,然后又是用中国剩余定理求答案。

    注意,有些地方直接乘会爆long long,按位乘可避免。

    AC代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    using namespace std;;
    
    typedef long long LL;
    
    void gcd(LL a, LL b, LL &d, LL &x, LL &y)
    {
        if (!b) { d = a; x = 1; y = 0; }
        else { gcd(b, a % b, d, y, x); y -= x * (a / b); }
    }
    
    LL quickmul(LL m, LL n, LL k)
    {
        m = (m % k + k) % k; n = (n % k + k) % k;   //变成较小的正数
        LL res = 0;
        while (n > 0)
        {
            if (n & 1)
                res = (res + m) % k;
            m = (m + m) % k;
            n = n >> 1;
        }
        return res;
    }
    
    //计算模n下a的逆。如果不存在逆,返回-1
    //ax=1(mod n)
    LL inv(LL a, LL n)
    {
        LL d, x, y;
        gcd(a, n, d, x, y);
        return d == 1 ? (x + n) % n : -1;
    }
    
    //n! % p
    LL fact(LL n, LL p)
    {
        LL ret = 1;
        for (int i = 1; i <= n; i++)  ret = ret * i % p;
        return ret;
    }
    
    LL comp(LL n, LL m, LL p)
    {
        if (n < 0 || m > n)  return 0;
        return fact(n, p) * inv(fact(m, p), p) % p * inv(fact(n - m, p), p) % p;
    }
    
    LL lucas(LL a, LL b, LL m)
    {
        LL ans = 1;
        while (a && b)
        {
            ans = quickmul(ans, comp(a % m, b % m, m), m) % m;
            a /= m; b /= m;
        }
        return ans;
    }
    
    //n个方程:x=a[i](mod m[i])
    LL china(int n, LL* a, LL* m)
    {
        LL M = 1, d, y, x = 0;
        for (int i = 0; i < n; i++)  M *= m[i];
        for (int i = 0; i < n; i++)
        {
            LL w = M / m[i];
            gcd(m[i], w, d, d, y);     
            x = (x + quickmul(quickmul(w,y, M),a[i],M)) % M;   //直接乘会爆long long,要用按位乘
        }
        return (x + M) % M;
    }
    
    int k;
    LL n, m;
    LL p[10 + 5],r[10 + 5];
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while (T--)
        {
            cin >> n >> m >> k;
            for (int i = 0; i < k; i++)
                cin >> p[i];
            for (int i = 0; i < k; i++)
                r[i] = lucas(n, m, p[i]);
            LL ans = china(k, r, p);
            cout << ans << endl;
        }
    
        return 0;
    }

    参考链接:https://www.cnblogs.com/linyujun/p/5199684.html

  • 相关阅读:
    MySQL Binlog解析(2)
    在线修改GTID模式
    官方online ddl
    pt-osc原理
    pt-osc使用方法
    python基本数据类型
    第一句python
    搭建私有云kodexplorer
    frp搭建
    Linux下快速分析DUMP文件
  • 原文地址:https://www.cnblogs.com/lfri/p/10458386.html
Copyright © 2011-2022 走看看