定义状态为前i个金币能组合成总金额为j的方案总数
状态转移方程为
和完全背包类似,可以化简成
因为这道题最后会爆long long int
在大神的博客里面学到了一招,将答案拆成两半,用两个dp数组存。一个存高18位,一个存低18位。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX_N 1005
using namespace std;
typedef long long int ll;
ll dp1[MAX_N], dp2[MAX_N];//dp1表示高18位,dp2表示低18位
ll INF = 1;
int main()
{
//freopen("1.txt", "r", stdin);
for (int i = 1; i <= 18; i++)
INF *= 10;
ll N, K;
while (cin >> N >> K)
{
int weight[MAX_N];
for (ll i = 1; i <= K; i++)
weight[i] = i;
memset(dp1, 0, sizeof(dp1));
memset(dp2, 0, sizeof(dp2));
for (ll i = 1; i <= K; i++)
for (ll j = 0; j <= N; j++)
{
if (i == 1)
dp2[j] = (j % weight[1] == 0) ? 1 : 0;
else if (j >= weight[i])
{
dp1[j] = dp1[j] + dp1[j - weight[i]] + (dp2[j] + dp2[j - weight[i]]) / INF;
dp2[j] = (dp2[j] + dp2[j - weight[i]]) % INF;
}
}
if (dp1[N])
printf("%I64d", dp1[N]);
printf("%I64d\n", dp2[N]);
}
return 0;
}