斯特灵数stirling
不管是从左边看还是从右边看,视线总是会被中间最高的给挡住
所以我们把左边和右边分组来看。
对于某一边,我们确定出能够看见的楼房,那么不能够看见的楼房就可以任意排列
我们把能看见的楼房,与下一个能看到的楼房(不包括下一个楼房)之间的楼看为一组
可以考虑现将最高的拿出来,那么可以考虑左边需要有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\n",ans);
}
}
return 0;
}
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。