题意:给定两个数n和k,问将n用1到k这k个数字进行拆分,有多少种拆分方法。例如:n=5,k=3 则有n=3+2,n=3+1+1,n=2+1+1+1,n=2+2+1,n=1+1+1+1+1共5种拆分方法
思路:dp[i][j]表示数字n的拆分序列中最大的数字为 j 的拆分方法。那么每次求dp[i][j]的时候对序列中有几个j进行枚举即可。此题需要注意的是高精度的处理,用long long不够存,那么考虑用两个long long 分别存结果的前一部分和后一部分。实际上判断最终结果有多大恐怕还得是先用数组模拟高精度测试一下大数据有多大才行。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define N 1005
struct node{
long long a,b;
}dp[N][1005],one;
int n,m;
long long inf;
struct node solve(int n,int m){
struct node tmp;
if(n<m)
return solve(n, n);
if(m==1 || n==0)
return one;
if(dp[n][m].a||dp[n][m].b)
return dp[n][m];
for(int i = 1;i*m<=n;i++){
tmp = solve(n-i*m, m-1);
dp[n][m].a+=(tmp.a+(tmp.b+dp[n][m].b)/inf);
dp[n][m].b=(dp[n][m].b+tmp.b)%inf;
}
tmp = solve(n, m-1);
dp[n][m].a+=(tmp.a+(tmp.b+dp[n][m].b)/inf);
dp[n][m].b=(dp[n][m].b+tmp.b)%inf;
return dp[n][m];
}
int main(){
int i,j;
for(i = 0,inf=1;i<18;i++)
inf *= 10;
one.a = 0;
one.b = 1;
scanf("%d %d",&n,&m);
for(i = 0;i<=n;i++)
for(j = 0;j<=m;j++)
dp[i][j].a = dp[i][j].b = 0;
solve(n,m);
if(dp[n][m].a)
printf("%lld",dp[n][m].a);
printf("%lld\n",dp[n][m].b);
return 0;
}