【noi 2.6_9283】&【poj 3088】Push Botton Lock(DP--排列组合 Stirling数)

题意:N个编号为1~N的数,选任意个数分入任意个盒子内(盒子互不相同)的不同排列组合数。

解法:综合排列组合 Stirling(斯特林)数的知识进行DP。C[i][j]表示组合,从i个数中选j个数的方案数;S[i][j]表示Stirling数,i个数分成j份的方案数;P[i]表示P(i,i)全排列。
分别从N个数中选i个数后,这i个数分成j份(j=1~i),进入j个盒子内,j个盒子有不同的排列。
因此,对于N个数的公式为:ans=sum{C[n][i]*sum{S[i][j]*P[j]}};

P.S.noi oj上的数据有误

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 using namespace std;
 6 #define N 110
 7 #define NN 100
 8 typedef long long LL;
 9 
10 LL C[N][N],S[N][N],P[N];
11 
12 void init()
13 {
14     C[1][0]=C[1][1]=1;
15     S[1][0]=0,S[1][1]=1;
16     P[1]=1;
17     for (int i=2;i<=NN;i++)
18     {
19       C[i][0]=C[i][i]=1;
20       S[i][0]=0,S[i][i]=1;
21       for (int j=1;j<i;j++)
22       {
23         C[i][j]=C[i-1][j-1]+C[i-1][j];
24         S[i][j]=S[i-1][j-1]+j*S[i-1][j];
25       }
26       P[i]=P[i-1]*i;
27     }
28 }
29 
30 int main()
31 {
32     init();
33     int T,n;
34     scanf("%d",&T);
35     for (int e=1;e<=T;e++)
36     {
37       scanf("%d",&n);
38       LL ans=0;
39       for (int i=1;i<=n;i++)
40       {
41         LL h=0;
42         for(int j=1;j<=i;j++)
43           h+=S[i][j]*P[j];
44         ans+=C[n][i]*h;
45       }
46       printf("%d %d %I64d
",e,n,ans);
47     }
48     return 0;
49 }
原文地址:https://www.cnblogs.com/konjak/p/6002954.html