「题解」「HDU3037」Saving Beans
Posted arextre
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「题解」「HDU3037」Saving Beans相关的知识,希望对你有一定的参考价值。
题目
不超过 (n) 个球放入 (m) 个盒子方案数,盒子可以为空,求方案数。
题解
网上有很多使用公式推导的方法,这里介绍一种纯隔板法分析的思路。
首先分析一个子问题:将 (x) 个球放进 (y) 个盒子的方案数,盒子可以为空。
由于 (y-1) 个板隔开 (y) 段,那么 (y) 个盒子等价于 (y-1) 个隔板。
画出 (x+y-1) 个位置,在这 (x+y-1) 个位置里面填入 (y-1) 个板子,剩下的位置放球。
如果板子是相邻的就说明这两块板隔开的盒子为空,反之这个盒子中球的个数就是这相邻两个板子中间的球的数量。
也就是说,“(x) 个球放进 (y) 个盒子的方案数,盒子可以为空”的方案数为 (C(x+y-1,y-1)) 或者 (C(x+y-1,x))。
回到这道题,由于题目要求 “不超过”,那么我们定义第 (m+1) 个盒子为垃圾箱,加入我们在 (m) 个盒子里面放入 (m‘(m‘le m)) 个球,那么垃圾箱里面就会放 (m-m‘) 个球。
通俗地讲,多余的球会放入垃圾箱。
那么,这道题就被我们转化为 “在 (m+1) 个盒子里面放入 (n) 个球”。
由于之前的推导,我们易知此题答案为 (C(n+m,m))。
#include<cstdio>
#define int long long
const int MAXP=100000;
int T,n,m,p;
int fac[MAXP+5],inv[MAXP+5];
inline int INV(int a,const int mod){
int ret=1,n=mod-2;
for(;n>0;n>>=1){
if(n&1)ret=ret*a%mod;
a=a*a%mod;
}
return ret;
}
inline int C(const int n,const int m,const int p){
if(n<m)return 0;
return fac[n]*INV(fac[m],p)%p*INV(fac[n-m],p)%p;
}
inline int lucas(const int n,const int m,const int p){
if(m==0)return 1;
return lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
inline void init(const int lim){
fac[0]=fac[1]=inv[1]=1;//注意 fac[0]=1, 因为可能要用到 0 的阶乘
for(int i=2;i<=lim;++i)fac[i]=fac[i-1]*i%p;
// for(int i=2;i<=lim;++i)inv[i]=inv[p%i]*(p-p/i)%p;
// for(int i=2;i<=lim;++i)inv[i]=inv[i]*inv[i-1]%p;
}
signed main(){
scanf("%lld",&T);
while(T--){
scanf("%lld%lld%lld",&n,&m,&p);
init(p);
printf("%lld
",lucas(n+m,n,p));
}
return 0;
}
以上是关于「题解」「HDU3037」Saving Beans的主要内容,如果未能解决你的问题,请参考以下文章