zoukankan      html  css  js  c++  java
  • HDU4372-Count the Buildings【第一类Stirling数】+【组合数】

    <题目链接>

    <转载于 >>> >

    题目大意:

    N座高楼,高度均不同且为1~N中的数,从前向后看能看到F个,从后向前看能看到B个,问有多少种可能的排列数。

    0 < N, F, B <= 2000

    解题分析:

    首先我们知道一个结论: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];

    #include<cstdio>  
    #include<cstring>  
    #include<cmath>    
    #include<iostream>  
    #include<algorithm>  
    #define LL long long  
    using namespace std;  
     
    #define mod 1000000007 
    const int maxn = 2000 + 200;
    LL c[maxn][maxn], s[maxn][maxn];  
    
    
    //第一类Stirling数s(p,k)的实际意义是:将p个物体排成k个非空循环排列的方法数
    void init() {           //第一类斯特灵数通项公式 : S[n][k]=(S[n-1][k-1]+(n-1)*S[n-1][k])
      for(int i = 1; i <= 2005; i++) {       
        s[i][0] = 0; s[i][i] = 1;
        for(int j = 1; j < i; j++) {
          s[i][j] = ((i-1)*s[i-1][j]+s[i-1][j-1]) % mod;   
        //考虑递推,把n个不同元素分成k个不同的环有两种转移。第一种,有可能是n−1个不同元素
        //分成k−1个不同的环,当前的第n个独立成一个元素。第二种可能是n−1个不同元素已经分好了k个不同的环,当前这个可以加进去。
        }
      }
    } 
    
    void init2() {                  //初始化组合数
      c[0][0] = 1;
      for(int i = 1; i <= 2005; i++) {
        c[i][0] = 1;
        for(int j = 1; j <= i; j++) {
          c[i][j] = c[i-1][j-1]+c[i-1][j];     //组合数可以用杨辉三角来表示,c[i][j]=它左上方的元素+它正上方的元素
          if(c[i][j] >= mod) c[i][j] -= mod;
        }
      }
    }
    
    int main() {
      init();
      init2();
      int T; cin >> T;
      while(T--) {
        int n, f, b; scanf("%d%d%d", &n, &f, &b);
    
        LL ans = (f+b-2 <= n && f+b-2 >= 1)? c[f+b-2][f-1]*s[n-1][f+b-2]% mod : 0; 
        //c[f+b-2][f-1]的作用就是,将已经排好顺序的(f-1)个环按从小到大的顺序挑出f-1栋楼放在左边
        printf("%lld
    ", ans);
      }
      return 0;
    }

    2018-08-12

  • 相关阅读:
    MapReduce1.x与MapReduce2.x差异
    刷题60—排序数组
    刷题59— 圆圈中最后剩下的数字
    刷题58—地图分析
    刷题57—单词的压缩编码
    刷题56—卡牌分组
    刷题55—车的可用捕获量
    刷题54—三维形体的表面积
    刷题53—按摩师
    刷题52—链表的中间结点
  • 原文地址:https://www.cnblogs.com/00isok/p/9465534.html
Copyright © 2011-2022 走看看