http://acm.hdu.edu.cn/showproblem.php?pid=4372
题意:n个房子在一条线上(n<=2000),高度分别为1~n,现在需要将房子这样放置:从最左往右能看到F个房子,从最右往左能看到B个房子,能看到的条件是 两者之间的房子都要低于这个房子。问这样的方案数。
思路: 额,这个东西呢,想通了也就 很简单的啦。
n座塔,高度分别1~n,那 那个最高的不就从哪边看 都是能被看到的吗,我们就假设它的位置是固定的咯,我们假设这个最高的为塔n。 然后咧,题目要求 塔n的左边至少要有 f - 1 个递增的塔嘛,,右边就是 至少 b - 1 个 递减的啦,递增递减其实没什么所谓啦,知道是单调的就行了。 然后咧,我们 就 把 剩下的 n - 1 个数 分组 然后咧,分成 f - 1 + b - 1组, 然后就是 每组 至少一个元素,然后多的话呢,就用这组最高的塔 表示这一组 的高度。 然后咧,就 从 这 f - 1 + b - 1 个组中,取 f - 1 个放到 塔n的左边(组合数) 乘起来就是答案了。额, n - 1 个数,分成 f - 1 + b - 1 的组, 那么 肯定能 保证 每个组的高度都是不一样的,那么 对于任意的 f - 1组,总存在唯一的 或者是单调递增的排列,或者是递减的排列。 对于剩下的 b - 1 组也是如此。 然后那个分组的其实就是 第一类 斯特林数 啦
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<iostream> #define LL long long #define ULL unsigned long long #define rep(i,j,k) for(int i=j;i<=k;i++) #define dep(i,j,k) for(int i=k;i>=j;i--) #define INF 0x3f3f3f3f #define mem(i,j) memset(i,j,sizeof(i)) #define make(i,j) make_pair(i,j) #define pb push_back using namespace std; const int N = 2010; const int mod = 1000000007; LL c[N][N]; LL s1[N][N]; void init() { c[0][0] = 1; rep(i, 1, N - 5) { c[i][0] = c[i][i] = 1; s1[i][0] = 0; s1[i][i] = 1; rep(j, 1, i - 1) { c[i][j] = (c[i - 1][j] % mod + c[i - 1][j - 1] % mod) % mod; s1[i][j] =( (i - 1) % mod * s1[i - 1][j] % mod + s1[i - 1][j - 1] % mod ) % mod; } } } int main() { init(); int t; int n, f, b; scanf("%d", &t); while(t--) { scanf("%d %d %d", &n, &f, &b); if( f + b - 2 > 2000) { puts("0"); continue ; } ///你不特胖,那你就和我一起re三遍吧 LL ans = c[f + b - 2][f - 1] % mod * s1[n - 1][f + b - 2] % mod; cout << ans <<endl; } return 0; }