斯特林数

洛谷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;
}




 

posted @ 2017-08-27 13:06  Mychael  阅读(219)  评论(0编辑  收藏  举报