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\n", _case, n, calc(n));

65     }

66     return 0;

67 }

 

你可能感兴趣的:(poj)