CF687C 硬币面额

1 CF687C 硬币面额

2 题目描述

时间限制 \(2s\) | 空间限制 \(256M\)

\(Pari\) 想从 \(Arya\) 那里购买一种昂贵的巧克力。她有 \(n\) 个硬币,第 \(i\) 个硬币的价值是 \(c_i\)。巧克力的价格为 \(k\) 元,因此 \(Pari\) 会给 \(Arya\) 支付总共 \(k\) 元价格的硬币。看着自己的硬币,\(Pari\) 想知道把硬币给了 \(Arya\) 后,\(Arya\) 能用这些硬币拼凑出多少不同的面额呢?

3 题解

我们观察数据范围,发现 \(n, k \le 500\),时间复杂度应该大致为 \(O(n^3)\) 数量级。我们再仔细观察题目要求:答案应该是拼出 \(k\) 的和的货币能拼出的所有面额。我们此时如果只考虑二维状态 \(dp_{i, j}\) 表示前 \(i\) 枚货币中选取和为 \(j\) 的货币可以拼凑出的面额数,会发现我们无法确定出最终答案,且转移比较困难。为了解决这个问题,我们可以增加一维,令 \(dp_{i, j, k}\) 表示前 \(i\) 枚货币中选取和为 \(j\) 的货币能否拼出面额 \(k\)。由于题目中所给出的数据范围很小,这种状态的设计不会使空间超限。注意这里为了方便计算,我们令 \(dp_{i, j, k}\) 这一状态中默认选取了第 \(i\) 枚货币。因为我们后面总有一种情况并不选取第 \(i\) 枚货币,所以我们无需担心可能找不到最优的情况。

接下来我们来研究转移。一共有两种方案:第 \(i\) 枚货币和其他数一起拼出 \(k\),第 \(i\) 枚货币不用于拼凑。对于第一种情况我们的转移是:

\[dp_{i, j, k} = dp_{i, j, k} | dp_{i-1, j - c_i, k - c_i} \]

这里我们用 \(|\) 是因为当 \(a | b\) 时,如果 \(a\)\(b\) 其中有一个为 \(1\),答案就是 \(1\)。这种赋值方案使得我们可以在 \(dp_{i-1, j-c_i, k-c_i}\)\(0\)\(dp_{i, j, k}\)\(1\) 时不让 \(0\) 影响答案,同时又在 \(dp_{i-1, j-c_i, k - c_i}\)\(1\) 时更新 \(dp_{i, j, k}\)。回到这种转移,其实际意义为:如果存在一种方案,使前 \(i-1\) 枚货币中选取和为 \(j-c_i\) 的一些货币可以凑出 \(k-c_i\) 这一面额,那么直接将第 \(i\) 枚货币加上以上条件中的面额,必定可以在前 \(i\) 枚货币中选取和为 \(j\) 的若干货币拼凑出面额 \(k\)

对于第二种情况,我们的转移是:

\[dp_{i, j, k} = dp_{i, j, k} | dp_{i-1, j-c_i, k} \]

这个意义就相对来说更简单了,我们不用第 \(i\) 个数来拼凑出 \(k\),只需要看前面是否有和为 \(j - c_i\) 且能拼凑出 \(k\) 的情况。

这里我们发现:第一维其实与普通背包中的第一位差不多,可以采用滚动数组滚掉。这样 \(dp\) 的状态就变成二维的了,可以节省大量空间。输出时只需要输出

4 代码(空格警告):

#include <iostream>
using namespace std;
const int N = 505;
int n, k, ans;
int c[N], dp[N][N], s[N];
int main()
{
    cin >> n >> k;
    for (int i = 1; i <= n; i++) cin >> c[i];
    dp[0][0] = 1;
    for (int i = 1; i <= n; i++)
    {
        for (int j = k; j >= c[i]; j--)
        {
            for (int l = k; l >= 0; l--)
            {
                if (l >= c[i]) dp[j][l] |= dp[j - c[i]][l - c[i]];
                dp[j][l] |= dp[j-c[i]][l];
            }
        }
    }
    for (int i = 0; i <= k; i++) if (dp[k][i]) s[++ans] = i;
    cout << ans << '\n';
    for (int i = 1; i <= ans; i++) cout << s[i] << " ";
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-18 10:42  David24  阅读(52)  评论(1编辑  收藏  举报