[ABC156E]Roaming--每日博文(4.3)

Cherrt的第一篇的题解哦~

题意

若n个不同的屋子里各有一个人,求经过 k k 次串门后各个屋子里人数的不同格局的数量。答案对 1 0 9 + 7 10^9+7 取模。

题解

首先,看一下数据范围,发现 k 1 0 9 k≤10^9 ——所以时间复杂度完全不能依赖k。

接着我们发现,当 k n k≥n 时,每种格局都是可能形成的。换句话说, k n k≥n 时相当于将n个相同的苹果放入 n n 个盘子里,求出盘子里苹果数量的格局。这时可以使用插板法,即 C ( n 1 , 2 n 1 ) C(n-1,2*n-1) (不懂请看福利)。

如果 k n k<n ,那么就不可能形成所有格局。这时考虑将所有格局的数量( C ( n 1 , 2 n 1 ) C(n-1,2*n-1) )减去所有无法得到的格局的数量。

易得,当空房的数量大于 k k 时不合法,即非空房的数量小于等于 n k n-k 时不合法。然后,我们可以枚举非空房的数量 i i ,累加即可。再次得到,当非空房的数量为i时,格局的数量为 C ( n , i ) C ( n 1 , i 1 ) C(n,i)*C(n-1,i-1) (不懂请看福利)。

于是思路就很清晰啦! 但是要注意一些东西,否则会死得一批得惨

卡点(注意点)

①逆元;

②刚才说过要去不满足要求的格局数量,所以要始终保持答案非负性;

③做阶乘逆元的时候,数组一定要开大;否则RE。

事实上难度并不是很大······也就普及+/提高吧。

福利

我知道阁下可能不懂那两个式子怎么推出来的。不着急,看个例子就明白了。

将n个相同苹果放到k个不同的盘子里,每个盘子可以为空,求格局数量?

假设有 2 × k 2×k 个苹果。我们可以考虑插板,即在 2 k 1 2*k-1 个间隙中插板,两个板之间苹果的数量减一就是该盘子内苹果的数量。

这是最基本的小学奥数啊

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxlen=200000;

int n,k,mod=1e9+7,ans=0ll;
int jc[5*maxlen+5];

int quick_power(int a,int b)
{
	int res=1;
	for (;b;b=b>>1,a=(a*a)%mod)
	{
		if (b&1)  res=(res*a)%mod;
	}
	return res;
}

int ny(int n)
{
	return quick_power(n,mod-2)%mod;
}

int C(int n,int k)
{
	if (k<=0||n==k)  return 1;
	if (2*k>n)  k=n-k;
	
	return ((jc[n]*ny(jc[n-k])%mod)*ny(jc[k]))%mod;
}

inline void get_all_jc()
{
	jc[0]=1;
	for (int i=1;i<=5*maxlen;i++)  jc[i]=(jc[i-1]*i)%mod;
}

signed main()
{
	cin>>n>>k;
	get_all_jc();
	
	if (k>n)  return cout<<C(2*n-1ll,n)<<endl,0;
	else
	{
		ans=C(2*n-1ll,n);
		for (int i=1;i<=n-k-1;i++)  ans=((ans-C(n,i)*C(n-1,i-1))%mod+mod)%mod;
		return cout<<ans<<endl,0;
	}
}

撒花✿✿ヽ(°▽°)ノ✿撒花

原创文章 19 获赞 27 访问量 1955

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/105300514
156