斯特灵数stirling

Count the Buildings

不管是从左边看还是从右边看,视线总是会被中间最高的给挡住

所以我们把左边和右边分组来看。

对于某一边,我们确定出能够看见的楼房,那么不能够看见的楼房就可以任意排列

我们把能看见的楼房,与下一个能看到的楼房(不包括下一个楼房)之间的楼看为一组

可以考虑现将最高的拿出来,那么可以考虑左边需要有F-1个房子成递增关系,那么可以将左边的房子分成F-1个组(环),右边有B-1个房子成递减关系,也是如此,这就让人YY到了第一类Stirling数,第一类Stirling数s(p,k)是将将p个物体排成k个非空循环排列的方法数(k个排列是有先后顺序的)。可以想到,每一组都是有顺序的(与环等价)。除此之外,还要计算组合数,就是在(F-1+B-1)组中取出F-1个到左边,乘上即是答案。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 2000+10;
const int MOD = 1000000007;
int n,f,b;
ll s[maxn][maxn];
ll c[maxn][maxn];
void init(){
	c[0][0] = 1;
	s[0][0] = 1;
	for(int i = 1; i < maxn; i++){
		c[i][0] = c[i][i] = 1;
		s[i][0] = 0;s[i][i] = 1;
		for(int j = 1; j < i; j++){
			c[i][j] = (c[i-1][j] + c[i-1][j-1])%MOD; 
			s[i][j] = ((i-1)*s[i-1][j]+s[i-1][j-1])%MOD; 
		} 
	}
}
int main(){
	int ncase;
	init();
	cin >> ncase;
	while(ncase--){
		scanf("%d%d%d",&n,&f,&b); 
		if(f+b-2>n){
			puts("0");
		}else {
			ll ans = (c[f+b-2][f-1]*s[n-1][b+f-2])%MOD; 
			printf("%I64d
",ans);
		}
	}
	return 0;
}
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
原文地址:https://www.cnblogs.com/spnooyseed/p/12870920.html