链接:
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-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 }