AcWing 1487. 取硬币
原题链接
简单
作者:
Tie
,
2020-04-09 22:55:07
,
所有人可见
,
阅读 1111
#include <iostream>
using namespace std;
const int N = 100010, MOD = 1e9 + 7;
int n1, n2, m; // n1种普通币,n2种纪念币,凑成面值m
int f[N];
// 背包问题:完全背包(普通币) + 0/1背包(纪念币)
// 时间复杂度: O(n*m)
// f[i][j]:1.只从前i种硬币中选,且总面值是j的选法的集合 2.数量
// 集合可以分为两种:不选硬币i + 选硬币i
// 不选硬币i: f[i][j] = f[i-1][j]
// 选硬币i后:1. 纪念币(0/1背包)f[i][j] = f[i-1][j] + f[i-1][j-p[i]]
// 选硬币i后:2. 普通币种(完全背包)f[i][j] = f[i-1][j] + f[i-1][j-p[i]] + f[i-1][j-2*p[i]] + ...
// 优化:f[i][j-p[i]] = f[i-1][j-p[i]] + f[i-1][j-2*p[i]] + f[i-1][j-3*p[i]] + ...
// f[i][j] = f[i-1][j] + f[i][j-p[i]]
// 二维优化成一维
int main() {
cin >> n1 >> n2 >> m;
f[0] = 1; // 一枚硬币都没有的时候,只有一种就是都不选
for (int i = 1; i <= n1; i ++ ) { // 普通币:完全背包
int p; // 第i种纪念币的面值是p
cin >> p;
for (int j = p; j <= m; j ++ ) f[j] = (f[j] + f[j - p]) % MOD;
}
for (int i = 1; i <= n2; i ++ ) { // 纪念币:0/1背包
int p;
cin >> p;
for (int j = m; j >= p; j -- ) f[j] = (f[j] + f[j - p]) % MOD;
}
cout << f[m] << endl;
return 0;
}
牛皮!tql