题目描述
给一组 n 枚邮票的面值集合和一个上限 k —— 表示信封上能够贴 k 张邮票。
请求出最大的正整数 m,满足 1 到 m 的面值都可以用不超过 k 张邮票表示出来。
输入格式
输入的第一行是两个整数,分别代表邮票上限 k 和邮票面值数 n。
自第二行起,共有 n 个整数,第 i 个整数代表第 i 种邮票的面值 ai。
输出格式
输出一行一个整数代表 m,若 m 不存在请输出 0。
输入样例
5 2
1 3
输出样例
13
样例解释
有 1 分和 3 分的邮票;你最多可以贴 5 张邮票。很容易贴出 1 到 5 分的邮资(用 1 分邮票贴就行了),接下来的邮资也不难:
- 6 = 3 + 3
- 7 = 3 + 3 + 1
- 8 = 3 + 3 + 1 + 1
- 9 = 3 + 3 + 3
- 10 = 3 + 3 + 3 + 1
- 11 = 3 + 3 + 3 + 1 + 1
- 12 = 3 + 3 + 3 + 3
- 13 = 3 + 3 + 3 + 3 + 1
然而,使用 5 枚 1 分或者 3 分的邮票根本不可能贴出 14 分的邮资。因此,答案为 13。
数据范围
对于 100% 的数据,保证 1 ≤ k ≤ 200,1 ≤ n ≤ 50,1 ≤ ai ≤ 104 。
题解
完全背包(优化2.0):
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 55, M = 200 * 1e4 + 10;
int n, k;
int w[N], f[M];
int main()
{
cin >> k >> n;
for (int i = 1; i <= n; i ++) cin >> w[i];
memset(f, 0x3f, sizeof f);
sort(w + 1, w + 1 + n);
f[0] = 0;
for (int i = 1; i <= n; i ++)
for (int j = w[i]; j <= w[i] * k; j ++)
if(f[j - w[i]] + 1 <= k) f[j] = min(f[j], f[j - w[i]] + 1);
for (int i = 1; i <= M; i ++)
if(f[i] == 0x3f3f3f3f)
{
cout << i - 1 << endl;
return 0;
}
}