NOIP2018 提高组 货币系统
数学,DP,背包
这道题主要考察数学。结论是:\((m,b)\) 中的元素一定是由 \((n,a)\) 中的元素选出的。证明如下:
假设 \((n,a)\) 中的元素为集合 \(A\),\((m,b)\) 中的元素为集合 \(B\)。定义 \(A\) 的一类数为 \(x \in A\),且 \(x\) 不能被 \(A\) 中其它数表出;\(A\) 的二类数为 \(x \in A\),且 \(x\) 能被 \(A\) 中其它数表出。\(B\) 的则相同。
- 结论 1:若 \(x\) 为 \(A\) 的一类数,则 \(x \in B\)。
反证法。假设 \(x\) 为 \(A\) 的一类数,且 \(x \not\in B\)。那么为了让 \((n,a)\) 和 \((m,b)\) 等价,一定存在一个集合 \(S\),使得 \(S\) 能够表出 \(x\),且 \(S \subseteq B\)。因为 \(A\) 中其它元素无法表出 \(x\),设 \(y \in S\),那么存在 \(y\) 无法被 \(A\) 中的元素表出,如果没有,说明 \(A\) 可以表出 \(x\)。由上我们知道 \(y \in B\),但是 \(y\) 不能被 \(A\) 的元素表出,\((n,a)\) 与 \((m,b)\) 不等价,矛盾。
- 结论 2:若 \(x \in B\),则 \(x \in A\)。
反证法。假设 \(x \in B\) 且 \(x \not\in A\),则 \(A\) 中一定存在一个子集 \(S\),使得 \(S\) 中的数均为 \(A\) 的一类数,且能够表出 \(x\)。由结论 1 可得,有 \(S \subseteq B\),那么 \(x\) 是多余的,要求 \(m\) 最小,所以 \(x\) 要删去。
现在我们证明了 \(B \subseteq A\),为了让 \(|B|\) 最小,我们只选 \(A\) 的一类数就可以了。
#include <bits/stdc++.h>
const int N = 105, M = 25005;
int n, a[N], ans;
bool f[M];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
std::cin >> n;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
std::sort(a + 1, a + 1 + n);
ans = 0;
for (int i = 1; i <= n; i++) {
if (!f[a[i]]) {
ans++;
}
f[a[i]] = true;
for (int j = a[i]; j <= a[n]; j++) {
f[j] |= f[j - a[i]];
}
}
std::cout << ans << '\n';
for (int i = 0; i <= a[n]; i++) {
f[i] = false;
}
}
return 0;
}

浙公网安备 33010602011771号