【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\n",e,n,ans); 47 } 48 return 0; 49 }