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 }
原文地址:https://www.cnblogs.com/Leohh/p/7384166.html