hdu4372--第一类斯特林数

题目描述:有n栋楼排成一排,高度分别为1, 2……n,从前向后看可以看到F栋楼,从后往前看可以看到B栋楼,问这n栋楼有多少种排列?

分析:先说一下第一类斯特林数吧。

        S(n, m)表示恰包含m个圈n个元素的排列数,则很容易证明有递推公式:S(n, m) = (n - 1) * S(n - 1, m) + S(n - 1, m - 1);

        方便记忆一下吧:假设当前有n - 1个元素,如果又来一个元素形成了m个圈,则当前n - 1个元素只能是m个圈或是m - 1个圈

            (1) 如果当前是m个圈,且又来一个元素仍然是m个圈,我们考虑把第n个元素插在第i个元素的后面且和第i个元素在同一个圈,则一共有(n - 1)* S(n - 1, m)

            (2) 如果当前是m - 1个圈,又来一个元素形成了m个圈,则第n个元素只能自己形成一个圈,则只有S(n - 1, m - 1)

      综上:S(n, m) = (n - 1) * S(n - 1, m) + S(n - 1, m - 1)

      第一类斯特林数还满足母函数关系:

           设fn(x) = x * (x - 1) * (x - 2) * …… *(x - n + 1), S(n, m)是fn(x)的展开式中x^m的系数。

       回到这个题上来:

          无论是从前看还是从后看,n一定可以被看到且是最后一个被看到的,我们考虑把剩下的n - 1个元素分成 f + b - 2个组,每组内部有排列,从这f + b - 2组中选出f - 1个组放在前面,容易得出ans = C(f + b - 2, f - 1) * S(n - 1, f + b - 2);

 1 #include <stdio.h>
 2 #include <string.h>
 3 #define mod 1000000007
 4 #define maxn 2005
 5 long long C[maxn][maxn], S[maxn][maxn];
 6 
 7 void get_S()
 8 {
 9      memset(C, 0, sizeof(C));
10      memset(S, 0, sizeof(S));
11 
12      C[0][0] = 1;
13      S[0][0] = 1;
14      for(int i = 1; i < maxn; i++)
15      {
16           C[i][0] = 1;
17           S[i][0] = 0;
18           for(int j = 1; j <= i; j++)
19           {
20                C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
21                S[i][j] = (((i - 1) * S[i - 1][j]) % mod + S[i - 1][j - 1]) % mod;
22           }
23      }
24      return ;
25 }
26 
27 int main()
28 {
29      get_S();
30      int T, n, f, b;
31      scanf("%d", &T);
32      while(T--)
33      {
34           scanf("%d%d%d", &n, &f, &b);
35           long long ans = C[f + b - 2][f - 1] * S[n - 1][f + b - 2] % mod;
36           printf("%I64d\n", ans);
37      }
38      return 0;
39 }
View Code

 

 

转载于:https://www.cnblogs.com/wangsouc/articles/3689158.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值