• HDU 4372 Count the Buildings:第一类Stirling数


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4372

    题意:

      有n栋高楼横着排成一排,各自的高度为1到n的一个排列。

      从左边看可以看到f栋楼,从右边看可以看到b栋楼,并且高的楼会挡住低的楼。

      问你这些楼有多少种排列方法。

    题解:

      由于高的楼会挡住低的楼,所以这些楼首先会被划分成f+b-2个区域(除去中间最高的楼),并且左边有f-1个,右边有b-1个。

      

      对于一个区域(假设在左边),这个区域由若干栋楼组成,并且最高的楼一定在最左边。

      那么,由一个区域中的元素组成的任意一个环排列,在这个区域中都有唯一的放法,因为要把最高的元素拉到最左边。

      

      所以,原题被简化为:将n-1个元素形成f+b-2个环排列,并将其中f-1个环放在左边的方法数。

      又是第一类Stirling数。

      · 将n-1个元素形成f+b-2个环排列的方法数 = S(n-1,f+b-2)

      · 将其中f-1个环放在左边的方法数 = C(f+b-2,f-1)

      所以答案为:S(n-1,f+b-2)*C(f+b-2,f-1)

      注:此题有不合法数据,要判断一下是否f+b-1>n,如果是,输出0(不合法)。

    AC Code:

     1 // n: tot    f: lef    b: rig
     2 // lef group = f-1
     3 // rig group = b-1
     4 // elem num = n-1
     5 // circle num = f+b-2
     6 // ans = s(n-1, f+b-2) * c(f+b-2, f-1)
     7 // s(n,k) = s(n-1,k-1) + (n-1)*s(n-1,k)
     8 
     9 #include <iostream>
    10 #include <stdio.h>
    11 #include <string.h>
    12 #define MAX_N 2005
    13 #define MOD 1000000007
    14 
    15 using namespace std;
    16 
    17 int n,f,b,t;
    18 long long s[MAX_N][MAX_N];
    19 long long c[MAX_N][MAX_N];
    20 
    21 void cal_stirling()
    22 {
    23     memset(s,0,sizeof(s));
    24     s[0][0]=1;
    25     for(int i=1;i<MAX_N;i++)
    26     {
    27         s[i][i]=1;
    28         for(int j=1;j<i;j++)
    29         {
    30             s[i][j]=(s[i-1][j-1]+(i-1)*s[i-1][j])%MOD;
    31         }
    32     }
    33 }
    34 
    35 void cal_combination()
    36 {
    37     memset(c,0,sizeof(c));
    38     c[0][0]=1;
    39     for(int i=1;i<MAX_N;i++)
    40     {
    41         c[i][0]=1;
    42         for(int j=1;j<=i;j++)
    43         {
    44             c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
    45         }
    46     }
    47 }
    48 
    49 int main()
    50 {
    51     cal_stirling();
    52     cal_combination();
    53     cin>>t;
    54     for(int cas=1;cas<=t;cas++)
    55     {
    56         cin>>n>>f>>b;
    57         if(f+b-1<=n) cout<<(s[n-1][f+b-2]*c[f+b-2][f-1])%MOD<<endl;
    58         else cout<<0<<endl;
    59     }
    60 }
  • 相关阅读:
    Java线程中run和start方法的区别
    dwr+spring集成
    Lucene入门
    struts2之单个文件上传
    利用jQuery接受和处理xml数据
    struts2之多个文件上传
    Google开源项目二维码读取与生成工具ZXing
    C# Regex 深入正则表达式
    android多分辨率多密度下界面适配方案
    [转]C#.net编程创建 Access 文件和 Excel 文件
  • 原文地址:https://www.cnblogs.com/Leohh/p/7384166.html
Copyright © 2020-2023  润新知