• ACM学习历程—HDU 5446 Unknown Treasure(数论)(2015长春网赛1010题)


    Problem Description
    On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician entered the cave because it is there. Somewhere deep in the cave, she found a treasure chest with a combination lock and some numbers on it. After quite a research, the mathematician found out that the correct combination to the lock would be obtained by calculating how many ways are there to pick m different apples among of them and modulo it with M . M is the product of several different primes.
     
    Input
    On the first line there is an integer T(T20) representing the number of test cases.

    Each test case starts with three integers n,m,k(1mn10^18,1k10) on a line where k is the number of primes. Following on the next line are k different primes p1,...,pk . It is guaranteed that M=p1p2pk10^18 and pi10^5 for every i{1,...,k}.
     
    Output
    For each test case output the correct combination on a line.
     
    Sample Input
    1
    9 5 2
    3 5
     
    Sample Output
    6

    题目要求一个大组合数模几个素数乘积的结果。

    大组合那块能通过Lucas得到对每个素数模的结果。

    然后再通过互质型的中国剩余定理可以得到最终结果。

    不过我的模板中国剩余定理里面乘法部分会爆long long。

    然后用大数优化了乘法部分,通过大数乘大数,模完后返回小数。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <set>
    #include <queue>
    #include <vector>
    #define LL long long
    #define UNIT 10
    
    using namespace std;
    
    const int maxK = 15;
    LL n, m, s[maxK], prime[maxK];
    int k;
    
    struct Bignum
    {
        int val[105];
        int len;
    
        Bignum()
        {
            memset(val, 0, sizeof(val));
            len = 1;
        }
    
        Bignum operator=(const LL &a)
        {
            LL t, p = a;
            len = 0;
            while (p >= UNIT)
            {
                t = p - (p/UNIT)*UNIT;
                p = p / UNIT;
                val[len++] = t;
            }
            val[len++] = p;
            return *this;
        }
    
        Bignum operator*(const Bignum &a) const
        {
            Bignum x;
            int i, j, up;
            int x1, x2;
            for (i = 0; i < len; i++)
            {
                up = 0;
                for (j = 0; j < a.len; j++)
                {
                    x1 = val[i]*a.val[j] + x.val[i+j] + up;
                    if (x1 >= UNIT)
                    {
                        x2 = x1 - x1/UNIT*UNIT;
                        up = x1 / UNIT;
                        x.val[i+j] = x2;
                    }
                    else
                    {
                        up = 0;
                        x.val[i+j] = x1;
                    }
                }
                if (up != 0)
                    x.val[i+j] = up;
            }
            x.len = i + j;
            while (x.val[x.len-1] == 0 && x.len > 1)
                x.len--;
            return x;
        }
    
        LL operator%(const LL &a) const
        {
            LL x = 0;
            for (int i = len-1; i >= 0; --i)
                x = ((x*UNIT)%a+val[i]) % a;
            return x;
        }
    };
    
    LL mulMod(LL x, LL y, LL p)
    {
        LL ans = 0;
        Bignum xx, yy;
        xx = x;
        yy = y;
        xx = xx*yy;
        ans = xx%p;
        return ans;
    }
    
    LL quickMod(LL a, LL b, LL p)
    {
        LL ans = 1;
        a %= p;
        while (b)
        {
            if (b&1)
            {
                ans = ans*a%p;
                b--;
            }
            b >>= 1;
            a = a*a%p;
        }
        return ans;
    }
    
    LL C(LL n, LL m, LL p)
    {
        if (m > n)
            return 0;
        LL ans = 1;
        for(int i = 1; i <= m; i++)
        {
            LL a = (n+i-m)%p;
            LL b = i%p;
            ans = ans*(a*quickMod(b, p-2, p)%p)%p;
        }
        return ans;
    }
    
    LL Lucas(LL x, LL y, LL p)
    {
        if (y == 0)
            return 1;
        return C(x%p, y%p, p)*Lucas(x/p, y/p, p)%p;
    }
    
    //EXGCD
    //求解方程ax+by=d,即ax=d mod(b)
    //扩展可求逆元
    //O(logn)
    void exgcd(LL a, LL b, LL &x, LL &y, LL &d)
    {
        if (b == 0)
        {
            x = 1;
            y = 0;
            d = a;
        }
        else
        {
            exgcd(b, a%b, y, x, d);
            y -= a/b*x;
        }
    }
    
    //中国剩余定理(互质)
    //其中a为除数数组,n为模数数组
    LL CRT(LL *a, LL *n, int len)
    {
        LL N = 1, ans = 0;
        for (int i = 0; i < len; i++)
        {
            N *= n[i];
        }
        for (int i = 0; i < len; i++)
        {
            LL m = N / n[i];
            LL x, y, d;
            exgcd(m, n[i], x, y, d);
            x = (x%n[i] + n[i]) % n[i];
            //ans = (ans + m*a[i]*x%N) % N;
            ans = (ans + mulMod(mulMod(m, a[i], N), x, N)) % N;
        }
        return ans;
    }
    
    void input()
    {
        scanf("%I64d%I64d%d", &n, &m, &k);
        for (int i = 0; i < k; ++i)
            scanf("%I64d", &prime[i]);
    }
    
    void work()
    {
        for (int i = 0; i < k; ++i)
            s[i] = Lucas(n, m, prime[i]);
        LL ans = CRT(s, prime, k);
        printf("%I64d
    ", ans);
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 0; times < T; ++times)
        {
            input();
            work();
        }
        return 0;
    }
  • 相关阅读:
    我终于会手打lct了!
    [模板]Dijkstra-优先队列优化-单源最短路
    99999999海岛帝国后传:算法大会
    正在加载中。。。。。
    【题解】CF1054D Changing Array(异或,贪心)
    【题解】P4550 收集邮票(概率期望,平方期望)
    【题解】CF149D Coloring Brackets(区间 DP,记忆化搜索)
    【笔记】斜率优化 DP
    CSP2021 游记
    【题解】洛谷P1502 窗口的星星
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4808191.html
Copyright © 2020-2023  润新知