POJ 3088 斯特林
题意:有一个n个按钮的锁,按下一些按钮打开门,有多少开门方式,其中,一些按钮可以选,可以不选,选中的按钮 可以分成一些集合,集合之间无序,是同时按下的。
分析:
1、首先选择 i 个按钮,组合数
2、枚举分成的集合
3、i 个按钮分成无序集合,第二类斯特林数
4、集合之间有序,排列数
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> using namespace std; const int maxn = 105; long long fac[maxn]; long long C[maxn][maxn]; long long stir[maxn][maxn]; void init() { fac[0] = fac[1] = 1; for(int i=2;i<maxn;i++) fac[i] = fac[i-1]*(long long)i; memset(C,0,sizeof(C)); C[0][0] = 1; C[1][0] = C[1][1] = 1; for(int i=2;i<maxn;i++) { C[i][0] = C[i][i] = 1; for(int j=1;j<i;j++) C[i][j] = C[i-1][j-1] + C[i-1][j]; } stir[1][1] = 1; for(int i=2;i<maxn;i++) for(int j=1;j<=i;j++) stir[i][j] = stir[i-1][j-1] + (long long)j*stir[i-1][j]; } int main() { //freopen("in.txt","r",stdin); int t; scanf("%d",&t); init(); int kase = 1; while(t--) { int n; scanf("%d",&n); long long ans = 0; for(int i=1;i<=n;i++) { for(int j=1;j<=i;j++) { ans+=(C[n][i]*fac[j]*stir[i][j]); } } printf("%d %d %I64d\n",kase++,n,ans); } return 0; }