hdu 3037 saving beans (lucas定理)

来源:互联网 发布:js获取当前unix时间戳 编辑:程序博客网 时间:2024/05/18 20:09

题目大意:求在n棵树保存不超过m个豆子的方法数,结果对p取模。 (n、m<=1000000000,p<100000且为质数)


分析:

由插板法,在n棵树保存i个豆子方案数为C(n+i-1,i)。

不超过m个豆子,则方案数为C(n+0-1,0)+C(n+1-1,0)+……+C(n+m-1,m)。

根据组合数性质:C(n,m)=C(n-1,m-1)+C(n-1,m),可将上式化简为C(n+m,m)

即所求结果为C(n+m,m)

考虑到n、m非常大,而p为10^5内的质数,因而可以使用lucas定理求出答案。


Lucas定理:通俗点来说就是把C(n,m)%p的中n,m化成p进制,然后分别求p进制下,n,m对应位的C(nk,mk)相乘对p取模。

证明如下:


#include<stdio.h>#include<algorithm>using namespace std;typedef long long LL;LL pow(LL a,LL b,LL p){    LL ans=1;    while(b)    {        if(b&1) ans=ans*a%p;        a=a*a%p;        b>>=1;    }    return ans;}LL C(LL n,LL m,LL p){    if(m>n||m<0) return 0;    if(n-m<m) m=n-m;    LL a=1,b=1;    for(int i=0;i<m;++i)    {        a=a*(n-i)%p;        b=b*(m-i)%p;    }    return a*pow(b,p-2,p)%p;}LL Lucas(LL n,LL m,LL p){    LL ans=1;    while(n&&m&&ans)    {        ans=ans*C(n%p,m%p,p)%p;        n/=p,m/=p;    }    return ans;}int main(){    int t;    LL n,m,p;    scanf("%d",&t);    while(t--)    {        scanf("%lld%lld%lld",&n,&m,&p);        printf("%lld\n",Lucas(n+m,m,p));    }    return 0;}


0 0
原创粉丝点击