题面

大秦 为你打开 题目传送门

题目翻译:

有 $n$ 种面值的硬币,面值分别为 $a_1,a_2,…,a_n$ ,数量分别为 $c_1,c_2,c_3,…,c_n$ ,请问在这些硬币的组合下,能够组成多少种不超过 $m$ 的面值。

思路

显而易见的,这是一道多重背包模板题。面值是体积,数量就是每一种物品数量,$n$ 是物品个数。

但是这里的题目是 “能够组成多少种不超过 $m$ 的面值 ”,所以设定如下状态:

1
2
dp[i]
// 表示是否可以组成面值为 i 的方案

往下就是正常步骤了,详见代码。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
using namespace std;

int n, m;
int a[110];
int c[110];
int top;
int v[100010];
int dp[100010];

void Input() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++) {
scanf("%d", &c[i]);
int cnt = 1;
while (c[i] >= cnt) {
v[++top] = cnt * a[i];
c[i] -= cnt;
cnt *= 2;
}
v[++top] = c[i] * a[i];
}
}

void Work() {
dp[0] = 1;
for (int i = 1; i <= top; i++) {
for (int j = m; j >= v[i]; j--) {
if (dp[j - v[i]]) {
dp[j] = 1;
}
}
}
int ans = 0;
for (int i = 1; i <= m; i++) {
ans += dp[i];
}
printf("%d", ans);
}

int main() {
Input();
Work();
return 0;
}