「题解」「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的主要内容,如果未能解决你的问题,请参考以下文章

hdu 3037 Saving Beans

HDU 3037:Saving Beans

HDU3037Saving Beans(组合数+lucas定理)

hdu 3037Saving Beans(卢卡斯定理)

J - Saving Beans (HDU - 3037)

Saving Beans HDU - 3037(卢卡斯定理)