zoukankan      html  css  js  c++  java
  • HDU 4372 Count the Buildings [第一类斯特林数]

    有n(<=2000)栋楼排成一排,高度恰好是1至n且两两不同。现在从左侧看能看到f栋,从右边看能看到b栋,问有多少种可能方案。

    T组数据, (T<=100000)


    自己只想出了用DP搞

    发现最高的楼一定能看到,分成了左右两个问题

    f[i][j]表示i栋楼从左面可以看到j栋方案数,转移枚举最高楼左面有几栋楼,乘上个组合数和剩下的排列

    问题是DP完了求ans需要O(n)枚举最高楼在哪........

    然后发现好多人用了第一类sirtling数

    考虑一栋被看到的楼,它会挡住它右面的几栋楼,这几栋楼可以任意排列都不会被看到

    我们把这样作为一组,然后发现去掉最高的楼后左面需要f-1组,右面需要b-1组

    一个组的最高元素必须在最左面,发现这样意味着是循环同构的(一种循环只有最高在最左合法),就是第一类sirtling数啊

    $ans={{f+b-2}choose {f-1}}*s(n-1,f+b-2)$

    然后本题G++迷之RE

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=2005,MOD=1e9+7;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,f,b;
    int c[N][N],s[N][N];
    void ini(int n){
        c[0][0]=1;
        for(int i=1;i<=n;i++){
            c[i][0]=c[i][i]=1;
            for(int j=1;j<i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
        }
        s[0][0]=1;
        for(int i=1;i<=n;i++){
            s[i][i]=1;
            for(int j=1;j<i;j++) s[i][j]=(s[i-1][j-1]+(ll)s[i-1][j]*(i-1)%MOD)%MOD;
        }
    }
    
    int main(){
        freopen("in","r",stdin);
        int T=read();
        ini(2000);
        while(T--){
            n=read();f=read();b=read();
            printf("%lld
    ",(ll)c[f+b-2][f-1]*s[n-1][f+b-2]%MOD);
        }    
    }
  • 相关阅读:
    OSI安全体系结构
    PHP 二维数组根据相同的值进行合并
    Java实现 LeetCode 17 电话号码的字母组合
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 16 最接近的三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 15 三数之和
    Java实现 LeetCode 14 最长公共前缀
  • 原文地址:https://www.cnblogs.com/candy99/p/6402737.html
Copyright © 2011-2022 走看看