poj 3088 组合计数,第二类斯特林数

题意:给出n个数字[1,n],问你可以组成多少种不同的序列,其中每一个序列由几个部分组成,每个部分包含几个数字,每部分内数字无序,部分之间数字有序。每个数字最多使用一次,可以不用。

思路:枚举从n个数字中选出i个数字(组合数),再枚举将这i个数字分成j个部分(第二类斯特林数),然后乘上j的全排列。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 
 6 const int N = 12;
 7 long long c[N][N];
 8 long long s[N][N];
 9 long long q[N];
10 
11 void init()
12 {
13     //第二类斯特林数
14     memset( s, 0, sizeof(s) );
15     s[0][0] = 1;
16     for ( int i = 1; i < N; i++ )
17     {
18         for ( int j = 1; j <= i; j++ )
19         {
20             s[i][j] = s[i - 1][j] * j + s[i - 1][j - 1];
21         }
22     }
23     //组合数
24     memset( c, 0, sizeof(c) );
25     c[0][0] = 1;
26     for ( int i = 1; i < N; i++ )
27     {
28         c[i][0] = 1;
29         for ( int j = 1; j <= i; j++ )
30         {
31             c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
32         }
33     }
34     //全排列数
35     q[0] = 1;
36     for ( int i = 1; i < N; i++ )
37     {
38         q[i] = q[i - 1] * i;
39     }
40 }
41 
42 long long calc( int n )
43 {
44     long long ans = 0;
45     for ( int i = 1; i <= n; i++ )
46     {
47         for ( int j = 1; j <= i; j++ )
48         {
49             ans += c[n][i] * s[i][j] * q[j];
50         }
51     }
52     return ans;
53 }
54 
55 int main ()
56 {
57     init();
58     int t;
59     scanf("%d", &t);
60     for ( int _case = 1; _case <= t; _case++ )
61     {
62         int n;
63         scanf("%d", &n);
64         printf("%d %d %lld
", _case, n, calc(n));
65     }
66     return 0;
67 }
原文地址:https://www.cnblogs.com/huoxiayu/p/4657107.html