题目描述
@发源于 小朋友最近特别喜欢球。有一天他脑子抽了,从口袋里拿出了N个不同的球,想把它们放到M个相同的盒子里,并且要求每个盒子中至少要有一个球,他好奇有几种放法,于是尝试编程实现,但由于他天天不好好学习,只会上B站看游泳教练,于是他向你求助。
输入输出格式
输入格式:
多组数据,每行两个数N,M。
输出格式:
每组数据一行,表示方案数。
输入输出样例
输入样例#1:
4 2 1 1
输出样例#1:
7 1
说明
【样例解释】
N=4,M=2
1,2 3 4
2,1 3 4
3,1 2 4
4,1 2 3
1 2,3 4
1 3,2 4
1 4,2 3
对于20%的数据,满足1≤N,M≤10;
对于100%的数据,满足1≤N,M≤100,数据组数≤10。
stirling数,递推公式s[i][j]=s[i-1][j]*j+s[i-1][j-1]
S(p,k)的一个组合学解释是:将p个物体划分成k个非空的不可辨别的(可以理解为盒子没有编号)集合的方法数。
k!S(p,k)是把p个人分进k间有差别(如:被标有房号)的房间(无空房)的方法数。
S(p,k)的递推公式是:S(p,k)=k*S(p-1,k)+S(p-1,k-1) ,1<= k<=p-1
边界条件:S(p,p)=1 ,p>=0 S(p,0)=0 ,p>=1
递推关系的说明:
考虑第p个物品,p可以单独构成一个非空集合,此时前p-1个物品构成k-1个非空的不可辨别的集合,方法数为S(p-1,k-1);
也可以前p-1种物品构成k个非空的不可辨别的集合,第p个物品放入任意一个中,这样有k*S(p-1,k)种方法。
高精度使用重载运算符会很方便
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 struct node{ 7 long long a[500],len; 8 node() 9 {memset(a,0,sizeof(a));len=0;} 10 }; 11 node f[101][101]; 12 node operator + (node c,node d) 13 { 14 node h; 15 h.len=max(c.len,d.len); 16 int i; 17 for(i=1;i<=h.len;i++){ 18 h.a[i]+=c.a[i]+d.a[i]; 19 if(h.a[i]>=10){ 20 h.a[i+1]+=h.a[i]/10; 21 h.a[i]%=10; 22 if(i==h.len)h.len++; 23 } 24 } 25 return h; 26 } 27 node operator * (node c,long long u) 28 { 29 node h; 30 h.len=c.len; 31 int i; 32 for(i=1;i<=h.len;i++){ 33 h.a[i]+=c.a[i]*u; 34 if(h.a[i]>=10){ 35 h.a[i+1]+=h.a[i]/10; 36 h.a[i]%=10; 37 if(i==h.len)h.len++; 38 } 39 } 40 return h; 41 } 42 int main() 43 {int n,m,i,j; 44 while (cin>>n>>m) 45 { 46 if (n<m) 47 { 48 printf("0 "); 49 } 50 else if (n==m) 51 { 52 printf("1 "); 53 } 54 else 55 { 56 for (i=0;i<=n;i++) 57 f[i][i].a[1]=1,f[i][1].a[1]=1,f[i][i].len=f[i][1].len=1; 58 for (i=2;i<=n;i++) 59 { 60 for (j=2;j<=i-1;j++) 61 f[i][j]=f[i-1][j]*j+f[i-1][j-1]; 62 } 63 64 for (i=f[n][m].len;i>=1;i--) 65 printf("%lld",f[n][m].a[i]); 66 printf(" "); 67 } 68 69 } 70 }