题意:
有n个盛食物的箱子,m个盛酒的箱子,只有同种箱子能叠在一起,只有不同种的箱子能相邻摆放,问所有酒箱垒出的高度都大于h的概率
思路:
需要求出所有摆放的情况总数和满足条件的情况数
枚举酒箱的堆数i,即把m分成i个不为0的数,由隔板法,情况总数为C(m-1,i-1)
这时食物箱的摆放会出现三种情况
i-1堆时,情况总数为C(n-1,i-2)
i堆时,情况总数为C(n-1,i-1)
i+1堆时,情况总数为C(n-1,i)
每个i下两种箱子的情况总数相乘即为总的情况总数
满足高度大于h的情况数是C(m-(h-1)*i,i-1),就相当于先在i堆中每堆放h-1个,然后将剩余的箱子数m-(h-1)*i分成i个不为0的数
最后求一下逆元相乘即可
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
int f,w,h;
long long f1[100005];
long long w1[100005];
long long mod=1e9+7;
long long fac[100005];
long long afac[100005];
long long powd(long long a,long long b)
{
long long ans=1;
while(b>0)
{
if(b%2==1)
ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
long long C(long long b,long long a)
{
long long ans=1;
if(a>b)
return 0;
ans = (fac[b]*afac[b-a]%mod)*afac[a]%mod;
return ans;
}
void gt(long long* a,int len)
{
for(int i=1;i<=len;i++)
{
a[i]=C(len-1,i-1);
}
}
int main()
{
fac[0]=1;
for(int i=1;i<=100000;i++)
fac[i]=fac[i-1]*i%mod;
for(int i=0;i<=100000;i++)
afac[i]=powd(fac[i],mod-2);
while(~scanf("%d%d%d",&f,&w,&h))
{
memset(f1,0,sizeof(f1));
memset(w1,0,sizeof(w1));
gt(f1,f);
gt(w1,w);
if(f==0)
{
if(w>h)
printf("1\n");
else
printf("0\n");
}
else if(w==0)
{
printf("1\n");
}
else
{
long long ans1=0;
long long ans2=0;
long long id=1;
while(id<=f && (id+1)<=w)
{
ans1=(ans1+f1[id]*w1[id+1]%mod)%mod;
ans2=(ans2+f1[id]*C(w-(id+1)*h-1,id)%mod)%mod;
id++;
}
id=1;
while(id<=f&&id<=w)
{
ans1=(ans1+2*f1[id]*w1[id]%mod)%mod;
ans2=(ans2+2*f1[id]*C(w-id*h-1,id-1)%mod)%mod;
id++;
}
id=1;
while(id<=w && (id+1)<=f)
{
ans1=(ans1+f1[id+1]*w1[id]%mod)%mod;
ans2=(ans2+f1[id+1]*C(w-id*h-1,id-1))%mod;
id++;
}
//cout<<ans1<<":"<<ans2<<endl;
printf("%lld\n",ans2*powd(ans1,mod-2)%mod);
}
}
}