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;
}
posted @ 2024-09-02 13:25  Unino  阅读(9)  评论(0)    收藏  举报