Lucas定理-saving beans

来源:互联网 发布:js 旋转木马图片轮播 编辑:程序博客网 时间:2024/06/08 05:05

解决问题:

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

利用了Lucas定理和大组合数取模的过程。

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

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

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

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

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

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

那么答案就是求Cn+m,m % p 的值。

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

 

 

标准程序:

 

#include<cstdio>#include<algorithm>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;}

原创粉丝点击