HDOJ 4372 第一类斯特林数

链接:

http://acm.split.hdu.edu.cn/showproblem.php?pid=4372

题意:

有一系列的楼房,高度从1~n,然后从左侧看能看到f个楼房,右侧看能看到b个楼房,问有多少个方案数满足。

题解:

首先我们知道一个结论:n的环排列的个数与n-1个元素的排列的个数相等,因为P(n,n)/n=(n-1)!。

可以肯定,无论从最左边还是从最右边看,最高的那个楼一定是可以看到的.

假设最高的楼的位置固定,最高楼的编号为n,那么我们为了满足条件,可以在楼n的左边分x-1组,右边分y-1组,

且用每组最高的那个元素代表这一组,那么楼n的左边,从左到右,组与组之间最高的元素一定是单调递增的,

且每组中的最高元素一定排在该组的最左边,每组中的其它元素可以任意排列(相当于这个组中所有元素的环排列)。右边反之亦然。

然后,可以这样考虑这个问题,最高的那个楼左边一定有x-1个组,右边一定有y-1个组,且每组是一个环排列,

这就引出了第一类Stirling数(n个人分成k组,每组内再按特定顺序围圈的分组方法的数目)。

我们可以先把n-1个元素分成x-1+y-1组,然后每组内部做环排列。再在所有组中选取x-1组放到楼n的左边。所以答案是

ans(n, f, b) = C[f + b - 2][f - 1] * S[n - 1][f + b - 2];

代码:

31 ll stir[MAXN][MAXN];
32 ll C[MAXN][MAXN];
33 
34 void init() {
35     stir[1][0] = 0;
36     stir[1][1] = 1;
37     rep(i, 2, MAXN) rep(j, 1, i + 1)
38         stir[i][j] = (stir[i - 1][j - 1] + (i - 1)*stir[i - 1][j]) % MOD;
39     rep(i, 1, MAXN) {
40         C[i][0] = C[i][i] = 1;
41         rep(j, 1, i) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
42     }
43 }
44 
45 int main() {
46     ios::sync_with_stdio(false), cin.tie(0);
47     init();
48     int T;
49     cin >> T;
50     while (T--) {
51         int n, f, b;
52         cin >> n >> f >> b;
53         cout << C[f + b - 2][f - 1] * stir[n - 1][f + b - 2] % MOD << endl;
54     }
55     return 0;
56 }
posted @ 2017-10-02 20:27  Flowersea  阅读(149)  评论(0编辑  收藏  举报