zoukankan      html  css  js  c++  java
  • 「题解」洛谷 P5020 货币系统

    题目

    P5020 货币系统

    简化题意

    给你一个集合 (A),让你找到元素最少的和集合 (A) 等价的集合 (B)

    等价指的是用 (A) 中元素能表出的使用 (B) 中元素也能表出,用 (A) 中元素不能表出的使用 (B) 中元素也不能表出。

    题解

    dp。本题的答案就是 (A) 中不能被 (A) 中其它元素表出的元素的个数。

    证明:

    先证明 (A) 中不能被 (A) 中其它元素表出的元素一定在 (B) 中。

    反证法。若 (x in A) 并且 (x) 不能被 (A) 中其它元素表出。设 (x otin 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
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    CSU 1122
    CSU 1256
    CSU 1240
    HDU 1874
    CSU 1004
    Problem F CodeForces 16E
    Problem E CodeForces 237C
    Problem C FZU 1901
    12-30
    2016-12-29
  • 原文地址:https://www.cnblogs.com/poi-bolg-poi/p/13661761.html
Copyright © 2011-2022 走看看