hdu-3037-Saving Beans(Lucas定理+大组合数取模)

Saving Beans


                                                                           Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)


Problem Description

Although winter is far away, squirrels have to work day and night to save beans. They need plenty of food to get through those long cold days. After some time the squirrel family thinks that they have to solve a problem. They suppose that they will save beans in n different trees. However, since the food is not sufficient nowadays, they will get no more than m beans. They want to know that how many ways there are to save no more than m beans (they are the same) in n trees.


Now they turn to you for help, you should give them the answer. The result may be extremely huge; you should output the result modulo p, because squirrels can’t recognize large numbers.


Input
The first line contains one integer T, means the number of cases.


Then followed T lines, each line contains three integers n, m, p, means that squirrels will save no more than m same beans in n different trees, 1 <= n, m <= 1000000000, 1 < p < 100000 and p is guaranteed to be a prime.
 
Output

You should output the answer modulo p.
 


Sample Input

2
1 2 5
2 1 5
 


Sample Output
3

3


题意:

求把m个果实放到n个树的方案数,并将答案对p求余。


题目链接:Saving Beans


解题思路:

将题目转化为方程x1+x2+x3+...+xn = m 的解的数目,即n个树上的果子数之和等于m,利用插板法思想,就是把m分

解成n个数之和,把m看成m个1,那么有m+1个空,以后每插入一个板子后,空都比之前多一个,m分成n个数之和只要

插n-1个板子,然后板子先后插是没有差别的,根据组合数知识,要除个(n-1)!,

(m+1)*(m+2)*...(m+n-1) = C(n+m-1,n-1)= C(n+m-1, m)

然后考虑从0~m所有果子个数的情况,利用组合数知识,C(n, k) + C(n,k+1) = C(n+1, k+1);

有 C(n-1,0)+C(n,1)+...C(n+m-1, m) = C(n, 0) +C(n,1)+...C(n+m-1, m) = C(n+m,m).

那么答案就是求C(n+m,m) % p 的值。

而Lucas定理就是专门解决类似于此的大组合数求余算法。


定理内容感觉还需要时间看看,先保存下模板

代码:

#include
#include

using namespace std;
typedef long long LL;
LL mod;
LL fac[100010];

LL pow_mod(LL x, LL n)  //快速幂取模
{
    LL sum = 1;
    while(n) {
        if(n & 1) sum = sum * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return sum;
}

void init() //初始化所需要的阶乘
{
    fac[0] = 1;
    for(int i = 1;i <= mod;i++)
        fac[i] =fac[i-1] * i % mod;
}

LL Lucas(LL n, LL m)//Lucas定理,计算C(n,m)%mod
{
    LL ans = 1;
    while(n && m) {
        LL a = n % mod, b = m % mod;
        if(a < b) return 0;
        ans = ans * fac[a] * pow_mod(fac[b]*fac[a-b] % mod, mod-2) % mod;
        n /= mod;
        m /= mod;
    }
    return ans;
}

int main()
{
    int T;
    LL n, m;
    scanf("%d",&T);
    while(T--) {
        scanf("%I64d%I64d%I64d",&n, &m, &mod);
        init();
        printf("%I64d\n", Lucas(n+m, m));
    }
    return 0;
}


你可能感兴趣的:(BASE-数论)