洛谷P1655 小朋友的球
题目描述
@发源于 小朋友最近特别喜欢球。有一天他脑子抽了,从口袋里拿出了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数
斯特林数解决的是这样一个问题:
n个不相同的元素,分割为m个集合,每个集合非空【至少有一个元素】,集合无序,问有多少种分割方法?
其实就是题目所述的分球问题
我们令f(n,m)为答案,根据dp的思想,对于第i个球,要么单独放一个盒子,要么在前i-1个球放完后加入其中一个盒子
那么就有f(n,m)=f(n-1,m-1)+j*f(n-1,m)
边界f(i,i)=1,i>=0
f(i,0)=0,i>=1
那么加上高精度就可以解了
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #define LL long long int using namespace std; const int maxn=105,INF=2000000000; int N,M; class BIG{ public: int n[maxn],len; BIG() {memset(n,0,sizeof(n));len=0;} }dp[maxn][maxn]; istream& operator >>(istream& in,BIG& a){ string s; in>>s; a.len=s.length(); for(int i=0;i<a.len;i++) a.n[i]=s[a.len-i-1]-'0'; return in; } ostream& operator << (ostream& out,const BIG& a){ if(!a.len) cout<<0; for(int i=a.len-1;i>=0;i--) out<<a.n[i]; return out; } BIG operator + (const BIG& a,const BIG& b){ BIG c; c.len=max(a.len,b.len); int carry=0,temp; for(int i=0;i<c.len;i++){ temp=a.n[i]+b.n[i]+carry; c.n[i]=temp%10; carry=temp/10; } if(carry) c.n[c.len++]=carry; return c; } BIG operator * (const BIG& a,const int& b){ int carry=0,temp; BIG c; c.len=a.len; for(int i=0;i<a.len;i++){ temp=a.n[i]*b+carry; c.n[i]=temp%10; carry=temp/10; } while(carry) c.n[c.len++]=carry%10,carry/=10; return c; } int main() { for(int i=0;i<=100;i++){ dp[i][i].len=dp[i][i].n[0]=1; } for(int i=1;i<=100;i++) for(int j=1;j<=i;j++){ dp[i][j]=dp[i-1][j]*j+dp[i-1][j-1]; } while(cin>>N>>M) cout<<dp[N][M]<<endl; return 0; }