这是我在sicily上排名第一的代码
题目很短,看似很简单,实则不然
主要的意思是求将n个元素的集合划分为m个子集的方法总数
找到递推公式 f(n,m)=f(n-1,m-1)+m*f(n-1,m)
但注意0<n<=50, 0<=m<=50 , 所以得用高精度去做
//希望大家多给点评论或建议的~
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
string p(string a,string b){
while( a.size()<b.size() )
a = "0"+a;
while( b.size()<a.size() )
b = "0"+b;
int l = a.size();
char *c = new char[l+2];
int carry = 0;
for(int i=1; i<=l; i++){
int sum = carry+a[l-i]-'0'+b[l-i]-'0';
c[l+1-i] = sum%10+'0';
carry = sum/10;
}
c[0] = carry+'0';
if (c[0]=='0'){
strncpy(c,c+1,l);
c[l] = 0;
}
else{
c[l+1] = 0;
}
string s(c);
delete c;
return s;
}
string multiply(string str,int n){
int l = str.size()+3;
char *c = new char[l];
c[l-1] = 0;
int carry = 0;
for(int i=str.size()-1; i>=0; i--){
int result = n*(str[i]-'0')+carry;
c[i+2] = '0'+result%10;
carry = result/10;
}
c[1] = '0'+carry%10;
c[0] = '0'+carry/10;
int beg = 2;
if (carry>=10)
beg = 0;
else if(carry>0)
beg = 1;
strncpy(c,c+beg,l);
c[l-1-beg] = 0;
string s(c);
delete c;
return s;
}
int main(){
int t;
scanf("%d",&t);
string dp[51][51];
dp[0][0] = "0";
for(int i=0; i<=50; i++)
for(int j=0; j<=50; j++){
if (i==0 || j==0 || i<j)
dp[i][j] = "0";
else if(i==j)
dp[i][j] = "1";
else{
string tmp = multiply(dp[i-1][j],j);
dp[i][j] = p(dp[i-1][j-1],tmp);
}
}
while( t-- ){
int n,m;
scanf("%d%d",&n,&m);
cout<<dp[n][m]<<endl;
}
return 0;
}