HDU 4372 Count the Buildings:第一類Stirling數

Leohh發表於2017-08-17

題目連結: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 }

 

相關文章