版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ljq1998/article/details/81178613
S(n,k)是n个数的集合的划分为k个非空集合方法的数目。(n个不同小球放到m个相同的盒子,每个盒子至少放一个球的种数)
例如S3,2 = 3因为3个元素的集合{a, b, c}有3种不同的划分方法:
{{a}, {b, c}}, {{b}, {a, c}}, {{c}, {a, b}}。可以知道Bell(n) = Sn,ki,( 1 <= ki <= n)。
递推式:S(n, k) = k * S(n - 1, k) + S(n - 1, k - 1)
边界条件: S(n, n) = 1, n >= 0
S(n, 0) = 0, n >= 1
解释:第n个物品来单独考虑。。我们要分为k个集合。。
1.可以把当前第n个物品作为一个集合,也就是S(n - 1, k - 1)中方法。
2.也可以把当前第n个物品放在其他的集合中来构成k个集合。也就是S(n - 1, k)中方法。
扩展:k! *S(n,k) 计数的是把n元素集合划分到k个可区分的盒子里且没有空盒子的划分个数。
#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
using namespace std;
const int mod = 10056;
int s[2000][2000];
int p[2000];
void init()
{
memset(s,0,sizeof(s));
s[0][0] = 1;
for(int i = 1;i < 1008;i++){
s[i][0] = 0;
for(int j = 1;j < i;j++){
s[i][j] = (j * s[i - 1][j] + s[i - 1][j - 1]) % mod;
}
s[i][i] = 1;
}
p[0] = p[1] = 1;
for(int i = 2;i <= 1008;i++){
p[i] = (p[i - 1] * i) % mod;
}
}
int main()
{
init();
int t,kk = 1;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
int ans = 0;
for(int i = 1;i <= n;i++){
ans = (ans + p[i] * s[n][i]) % mod;
}
printf("Case %d: %d\n",kk++,ans);
}
return 0;
}