题目地址:点击打开链接
dp[i][j]表示前i种硬币组成j元的方案数。
状态转移方程:dp[i][j] =∑(dp[i-1][j-k*v[i]]).
递推递归都可以写。
也可以用母函数写,注意母函数只能预处理的时候跑完,不然超时。
递推:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 8e3+5;
ll dp[6][maxn], n, v[6] = {0, 1, 5, 10, 25, 50};
void init()
{
dp[0][0] = 1;
for(int i = 1; i <= 5; i++)
for(int j = 0; j < maxn; j++)
for(int k = 0; j-k*v[i] >= 0; k++)
dp[i][j] += dp[i-1][j-k*v[i]];
}
int main(void)
{
init();
while(cin >> n)
printf("%lld\n", dp[5][n]);
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 8e3+5;
typedef long long ll;
ll dp[5][maxn], n, v[5] = {1, 5, 10, 25, 50};
ll dfs(int i, int j)
{
if(i==0) return dp[i][j] = 1;
if(dp[i][j] != -1) return dp[i][j];
dp[i][j] = 0;
for(int k = 0; j-k*v[i] >= 0; k++)
dp[i][j] += dfs(i-1, j-k*v[i]);
return dp[i][j];
}
int main(void)
{
memset(dp, -1, sizeof(dp));
while(cin >> n)
printf("%lld\n", dfs(4, n));
return 0;
}
母函数:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 8e3+5;
typedef long long ll;
ll a[5] = {1, 5, 10, 25, 50};
ll c1[maxn], c2[maxn];
int main(void)
{
int n;
memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
for(int i = 0; i < maxn-1; i++)
c1[i] = 1;
for(int i = 1; i <= 4; i++)
{
for(int j = 0; j <= maxn-1; j++)
for(int k = 0; j+k <= maxn-1; k += a[i])
c2[j+k] += c1[j];
for(int j = 0; j <= maxn-1; j++)
c1[j] = c2[j], c2[j] = 0;
}
while(cin >> n)
printf("%lld\n", c1[n]);
return 0;
}