题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=4372
题目大意
有
n
个建筑排成一列,它们的高度是在
思路
第一类斯特林数
s1[i][j]=i
个互不相同的物品,划分成
j
个环的方案数。
递推式的解释:对于第 i 个物品,如果前
实际上,一个长度为
n
的环的排列的个数就等于
注意到建筑物所有的排列的情形都类似于上图:所有的橙色建筑都是能从前方或者后方被看到的,所有的黄色建筑都是看不到的。并且最高的那个建筑物从前或从后都能看到,能看到的建筑物总数为
F+B−1
。我们把所有的建筑物划分成
F+B−1
组,每组里只能看到组内最高的那个元素。那么在最高的楼前面的组里,每组里最高的楼一定是在每组里的最前面,在最高的楼后面的组里,每组里最高的楼一定是在每组里的最后面,那么假如确定了一个组里的元素,并且组里共
n
个元素,则这个组的所有排列的方案数是
以最高的那个建筑物为中点分开看,能被前面看到的建筑物(不算最高的那个)的个数是 F−1 ,能被后面看到的建筑物(不算最高的那个)的个数是 B−1 ,这意味着最高的楼的左边有 F−1 组,右边有 B−1 组。
除掉最高的那个建筑后,还有
n−1
个建筑,它们分成
F+B−2
组环排列,可以构成
s1[n−1][F+B−2]
个方案,然后我们要在这
F+B−2
组里,选择其中
F−1
组放到前面,
B−1
组放到后面,这个操作的方案数是
CF−1F+B−2
。根据乘法原理,最终的答案为:
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 2200
#define MOD 1000000007
using namespace std;
typedef long long int LL;
LL s1[MAXN][MAXN],C[MAXN][MAXN];
void GetCombination()
{
for(int i=1;i<MAXN;i++)
{
C[i][0]=1%MOD;
C[i][i]=1%MOD;
for(int j=1;j<i;j++)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
}
}
void GetFirstStirling()
{
for(int i=1;i<MAXN;i++)
{
s1[i][0]=0;
s1[i][i]=1;
for(int j=1;j<i;j++)
s1[i][j]=(((i-1)*s1[i-1][j])%MOD+s1[i-1][j-1])%MOD;
}
}
int main()
{
GetCombination();
GetFirstStirling();
int T;
scanf("%d",&T);
while(T--)
{
LL n,f,b;
scanf("%lld%lld%lld",&n,&f,&b);
printf("%lld\n",C[f+b-2][f-1]*s1[n-1][f+b-2]%MOD);
}
return 0;
}