码迷,mamicode.com
首页 > 其他好文 > 详细

HDU4372 Count the Buildings

时间:2020-07-27 23:42:07      阅读:62      评论:0      收藏:0      [点我收藏+]

标签:line   ons   name   高度   pac   class   ++   lin   splay   

Description

现在有一列楼,共 \(n\) 个,从前面看是 \(f\) 个,从后面看有 \(b\) 个,楼的高度是一个排列

这里能看见得满足上升子序列

求有多少种的排列满足条件

\(n,f,b\le 2000\)

Solution

一定能看到最高的那个楼,所以该正反的序列就都以高度为 \(n\) 的为结尾

然后就是在剩下的 \(n-1\) 个里面选 \(b-1\) 个构成下降序列扔后面,选 \(f-1\) 个构成上升序列扔前面

所以这 \(n\) 个数被分组了,而且就直接是圆排列……

再想上这几个组再组合一下可以分成前面的 \(f-1\) 个和后面的 \(b-1\) 个,所以

\[ans=\binom {(b-1)+(f-1)} {f-1}\times S(n-1,(b-1)+(f-1)) \]

\(O(n^2)\) 预处理斯特林数,和组合数(这里考虑到爆空间,我用了线性的……)

Code

#include<bits/stdc++.h>
using namespace std;
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k==‘-‘) f=-1;
		while(isdigit(k)) res=res*10+k-‘0‘,k=getchar();
		return res*f;
	}
	const int mod=1e9+7;
	const int N=4010;
	int n,f,b,s[N][N],inv[N],fac[N];
	inline int C(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;}
	inline void work()
	{
		n=read(); f=read(); b=read(); 
		printf("%lld\n",1ll*s[n-1][b+f-2]*C(b+f-2,f-1)%mod);
		return ;
	}
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	signed main()
	{
		s[1][1]=1; inv[1]=inv[0]=fac[0]=1;
		for(int i=1;i<N;++i) fac[i]=1ll*fac[i-1]*i%mod;
		for(int i=2;i<N;++i) inv[i]=mod-1ll*mod/i*inv[mod%i]%mod;
		for(int i=1;i<N;++i) inv[i]=1ll*inv[i-1]*inv[i]%mod;
		for(int i=2;i<N;++i) for(int j=1;j<=i;++j) s[i][j]=add(s[i-1][j-1],1ll*(i-1)*s[i-1][j]%mod);
		int T=read(); while(T--) work();
		return 0;
	}
}
signed main(){return yspm::main();}

HDU4372 Count the Buildings

标签:line   ons   name   高度   pac   class   ++   lin   splay   

原文地址:https://www.cnblogs.com/yspm/p/13387082.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!