HDU-5446-UnknownTreasure(组合数,中国剩余定理)

Posted ydddd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU-5446-UnknownTreasure(组合数,中国剩余定理)相关的知识,希望对你有一定的参考价值。

链接:

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

题意:

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 n of them and modulo it with M. M is the product of several different primes.

思路:

lucas定理,p为素数时。
C(n, m) = C(n/p, m/p)+C(n%p, m%p).
对每个pi算出值,然后中国剩余定理求解。
因为数值较大。。很容易溢出,快速乘,顺序也会导致溢出。。
求逆元的时候,用快速幂会溢出,可以把快速幂里面的乘法用快速乘。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<math.h>
#include<vector>

using namespace std;
typedef long long LL;
const int INF = 1e9;

const int MAXN = 1e5+10;
const int MOD = 1e9+7;

LL F[MAXN], Finv[MAXN];
LL P[MAXN], A[MAXN];

LL MulMod(LL a, LL b, LL mod)
{
    LL res = 0;
    while(b>0)
    {
        if (b&1)
            res = (res+a)%mod;
        a = (a+a)%mod;
        b >>= 1;
    }
    return res;
}

LL PowMod(LL a, LL b, LL mod)
{
    LL res = 1;
    while(b>0)
    {
        if (b&1)
            res = res*a%mod;
        a = a*a%mod;
        b >>= 1;
    }
    return res;
}

void Init(LL n, LL m, LL mod)
{
    F[0] = F[1] = 1;
    for (LL i = 2;i <= n;i++)
        F[i] = F[i-1]*i%mod;
    Finv[m] = PowMod(F[m], mod-2, mod);
    Finv[n-m] = PowMod(F[n-m], mod-2, mod);
}

LL Comb(LL n, LL m, LL mod)
{
    if (m > n)
        return 0;
    if (m == n)
        return 1;
    Init(n, m, mod);
    return F[n]*Finv[m]%mod*Finv[n-m]%mod;
}

LL Lucas(LL n, LL m, LL mod)
{
    if (m == 0)
        return 1;
    return MulMod(Lucas(n/mod, m/mod, mod), Comb(n%mod, m%mod, mod), mod);
}

void ExGCD(LL a, LL b, LL &x, LL &y)
{
    if (b == 0)
    {
        x = 1, y = 0;
        return;
    }
    ExGCD(b, a%b, x, y);
    LL tmp = x;
    x = y;
    y = tmp-a/b*y;
}

LL CRT(int k)
{
    LL Pm = 1;
    LL res = 0;
    for (int i = 1;i <= k;i++)
        Pm *= P[i];
    for (int i = 1;i <= k;i++)
    {
        LL x, y;
        LL mi = Pm/P[i];
        ExGCD(mi, P[i], x, y);
        res = (res+MulMod(MulMod(x, mi, Pm), A[i], Pm))%Pm;
    }
    return (res+Pm)%Pm;
}

int main()
{
    int t, k;
    LL n, m;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%lld%lld%d", &n, &m, &k);
        for (int i = 1;i <= k;i++)
            scanf("%lld", &P[i]);
        for (int i = 1;i <= k;i++)
            A[i] = Lucas(n, m, P[i]);
        printf("%lld
", CRT(k));

    }

    return 0;
}

以上是关于HDU-5446-UnknownTreasure(组合数,中国剩余定理)的主要内容,如果未能解决你的问题,请参考以下文章