「题解」洛谷 P5020 货币系统

题目

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;
}
posted @ 2020-09-13 15:56  yu__xuan  阅读(124)  评论(0编辑  收藏  举报