E - Roaming-AtCoder Beginner Contest 156

E - Roaming

题意:

有一栋大楼有n个房间,编号从1到n。我们可以从大楼的任何房间搬去任何其他房间。让我们把下面的事件称为移动:某个房间里的人去另一个房间j(i≠j)。
最初,大楼里每个房间都有一个人。
求k次移动后n个房间的状态数。结果对1e9+7取模。

解题思路:

每个房间状态:有人,无人;
在移动操作后可能有i个房间无人,枚举无人房间数,每种状态下又根据(n-i)个房间人数产生子状态,此时考虑计算n个人分到(n-i)个房间的可能状态数。
将n个人分到(n-i)个房间~~(排列组合题)~~后续组合数处理。
(在n个人形成的n-1个空中放入n-i-1个插板分成n-i份有C(n-i-1,n-1)种可能。
可操作次数为K,所以i的最大值为min(k,n-1),枚举边界
求和:E - Roaming-AtCoder Beginner Contest 156_第1张图片

代码:

#include
#define ll long long
#define p 1000000007
using namespace std;
ll f[200005],ni[200005];
ll quickpow(ll a,ll b)
{
	ll res=1;
	while(b)
	{
		if(b&1)
		res=res*a%p;
		a=a*a%p;
		b>>=1;
	}return res;
}
ll zuhe(ll n,ll m)
{		ll sum;
	sum=f[n]*ni[n-m]%p*ni[m]%p;
	return sum;
}
int main()
{
	ll n,k;scanf("%lld%lld",&n,&k);
	ll a=min(k,n-1);ll sum=1;
	f[0]=1;ni[0]=quickpow(f[0],p-2)%p;
	for(int i=1;i<=n;++i) 
	{
	f[i]=f[i-1]*i%p;ni[i]=quickpow(f[i],p-2)%p;	
	}
	for(int i=1;i<=a;++i)
	{
	sum=(sum+zuhe(n,i)*zuhe(n-1,i)%p)%p;
		
	}
	printf("%lld",sum);
}

你可能感兴趣的:(atcoder)