题意:给出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 }
时间: 2024-10-06 00:58:21