//dp[i][j] := 用前i种价格配出金钱j的方案数,则:
//dp[i][j]=dp[i-1][j]+dp[i-1][j-i]+dp[i-1][j-2*i]+...+dp[i-1][j-n*i](ps:j-n*i>=0,这个思想似乎从poj2229想到的,但不知道是不是0.0)
//方法:大概就是缺什么就补什么,另外,这里大数溢出的情况,从网上学了一个东西用两个数字拼成大数的做法,0.0
//dp[i][j][0]:表示高位;dp[i][j][1]:表示低位
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
unsigned long long dp[110][1010][2];
const unsigned long long limit=100000000000000000;
int main()
{
int N,K;
//freopen("3181.txt","r",stdin);
while(~scanf("%d%d",&N,&K))
{
memset(dp,0,sizeof(dp));
for(int i=0;i<=N;i++)
{
dp[1][i][1]=1;
dp[1][i][0]=0;
}
for(int i=2;i<=K;i++)
{
for(int j=0;j<=N;j++)
{
for(int k=j;k>=0;k=k-i)
{
dp[i][j][0]+=dp[i-1][k][0];
dp[i][j][1]+=dp[i-1][k][1];
dp[i][j][0]+=dp[i][j][1]/limit;
dp[i][j][1]=dp[i][j][1]%limit;
}
}
}
if(dp[K][N][0])
{
printf("%llu",dp[K][N][0]);
}
printf("%llu\n",dp[K][N][1]);
}
return 0;
}
当然,这个复杂度是O(n^3),不过还可以再简化;
dp[i][j]=dp[i-1][j]+ dp[i-1][j-i]+dp[i-1][j-2*i]+...+dp[i-1][j-n*i](ps:j-n*i>=0)用j-i代替j,得:
dp[i][j-i]=dp[i-1][j-i]+dp[i-1][j-2*i]+dp[i-1][j-3*i]+...+dp[i-1][j-n*i](ps:j-n*i>=0)
联立2式,得:
dp[i][j]=dp[i-1][j]+dp[i][j-i];
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
unsigned long long dp[110][1010][2];
const unsigned long long limit=100000000000000000;
int main()
{
int N,K;
//freopen("3181.txt","r",stdin);
while(~scanf("%d%d",&N,&K))
{
memset(dp,0,sizeof(dp));
for(int i=0;i<=N;i++)
{
dp[1][i][1]=1;
dp[1][i][0]=0;
}
for(int i=2;i<=K;i++)
{
for(int j=0;j<=N;j++)
{
if(j<i)
{
dp[i][j][0] = dp[i - 1][j][0];
dp[i][j][1] = dp[i - 1][j][1];
}
else
{
dp[i][j][0]+=(dp[i-1][j][0]+dp[i][j-i][0]);
dp[i][j][1]+=(dp[i-1][j][1]+dp[i][j-i][1]);
dp[i][j][0]+=dp[i][j][1]/limit;
dp[i][j][1]=dp[i][j][1]%limit;
}
}
}
if(dp[K][N][0])
{
printf("%llu",dp[K][N][0]);
}
printf("%llu\n",dp[K][N][1]);
}
return 0;
}