「题解」洛谷 P5020 货币系统
题目
简化题意
给你一个集合 \(A\),让你找到元素最少的和集合 \(A\) 等价的集合 \(B\)。
等价指的是用 \(A\) 中元素能表出的使用 \(B\) 中元素也能表出,用 \(A\) 中元素不能表出的使用 \(B\) 中元素也不能表出。
题解
dp。本题的答案就是 \(A\) 中不能被 \(A\) 中其它元素表出的元素的个数。
证明:
先证明 \(A\) 中不能被 \(A\) 中其它元素表出的元素一定在 \(B\) 中。
反证法。若 \(x \in A\) 并且 \(x\) 不能被 \(A\) 中其它元素表出。设 \(x \notin B\)。
因为 \(A\) 和 \(B\) 是等价的,所以 \(B\) 中一定存在 \(b_1,b_2,\dots b_k\) 可以表出 \(x\)。然后 \(A\) 中一定存在元素可以表出 \(b_1,b_2,\dots, b_k\),那么 \(x\) 可以由 >\(A\) 中元素表出,与事实不符。证毕。
再证明 \(A\) 中能被 \(A\) 中其它元素表出的元素一定不在 \(B\) 中。
反证法。若 \(x \in A\) 并且 \(x\) 能被 \(a_1,a_2,\dots,a_k\) 表出。设 \(x \in B\)。
因为 \(A\) 和 \(B\) 是等价的,所以 \(B\) 中元素可以表出 \(a_1,a_2,\dots,a_k\),也就可以表出 \(x\)。与 \(B\) 中元素尽量少的事实不符。证毕。因为以上两点,所以本题的答案就是 \(A\) 中不能被 \(A\) 中其它元素表出的元素的个数。证毕。
将 \(A\) 中元素从小到大排序,\(f_i\) 表示用一部分数能否表示出 \(i\)。
最小的元素一定不能被其它元素表示,所以用最小的元素去更新 \(f\) 数组,然后每次更新后可以判断出 \(A\) 中下一个元素能否被表示。不断更新即可。
Code
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 25001
int t, n, ans, a[101], f[M];
int main() {
scanf("%d", &t);
while (t--) {
memset(f, 0, sizeof f);
scanf("%d", &n), ans = n, f[0] = 1;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
std::sort(a + 1, a + n + 1);
for (int i = 1; i <= n; ++i) {
if (f[a[i]]) --ans;
else {
for (int j = a[i]; j <= a[n]; ++j) {
f[j] |= f[j - a[i]];
}
}
}
printf("%d\n", ans);
}
return 0;
}