题目描述
@发源于 小朋友最近特别喜欢球。有一天他脑子抽了,从口袋里拿出了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。
算法分析
-
简单的动态规划,但是要加上高精度运算,不然只能得 2020 分。本题和 放苹果 有些类似,但是盒子不能空着不放,也就是楼下所说的 Stirling数,应用于组合数学领域
-
状态转移方程:f[i][j]=f[i-1][j-1]+f[i-1][j] imes jf[i][j]=f[i−1][j−1]+f[i−1][j]×j
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define inf 999999999 #define For(i,a,b) for(i=a;i<=b;++i) #define rep(i,a,b) for(i=a;i>=b;--i) #define mm(a,b) memset(a,b,sizeof(a)) #define ll long long using namespace std; ll read(){ ll sum=0,flag=1; char c=getchar(); while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();} while(c>='0'&&c<='9')sum=sum*10+c-'0',c=getchar(); return sum*flag; } ll maxx(ll x,ll y){ if(x<y)return y; return x; } ll minn(ll x,ll y){ if(x<y)return x; return y; } ll abss(ll x){ if(x>=0)return x; return -x; } struct node{ ll a[500],len; node(){mm(a,0);len=0;}//记得初始化 }; node t[111][111]; node operator + (node c,node d){ node h;h.len=maxx(c.len,d.len); int i; for(i=1;i<=h.len;i++){ h.a[i]+=c.a[i]+d.a[i]; if(h.a[i]>=10){ h.a[i+1]+=h.a[i]/10; h.a[i]%=10; if(i==h.len)h.len++; } } return h; } node operator * (node c,ll u){ node h;h.len=c.len; int i; for(i=1;i<=h.len;i++){ h.a[i]+=c.a[i]*u; if(h.a[i]>=10){ h.a[i+1]+=h.a[i]/10; h.a[i]%=10; if(i==h.len)h.len++; } } return h; } int main(){ ll i,j,m,n; For(i,1,100)t[i][0].a[1]=0,t[i][i].a[1]=t[i][1].a[1]=1,t[i][0].len=t[i][i].len=t[i][1].len=1; For(i,2,100){ For(j,2,i-1){ t[i][j]=t[i-1][j-1]+t[i-1][j]*j; } } while(scanf("%lld%lld",&m,&n)!=EOF){ if(n==0||n>m){printf("0 ");continue;} rep(i,t[m][n].len,1)printf("%lld",t[m][n].a[i]); printf(" "); } return 0; }