Count the Buildings ( s1 )

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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Willems/p/10964256.html