求助
  • 板块灌水区
  • 楼主一咕咕一
  • 当前回复3
  • 已保存回复3
  • 发布时间2025/2/8 10:25
  • 上次更新2025/2/8 10:38:47
查看原帖
求助
772815
一咕咕一楼主2025/2/8 10:25

Markdown:

~~题解前几个怎么全是火车头。。~~

这道题目的算法是背包 DP ,不难发现,我们亲爱的“题目翻译”把题目给精简化了,所以题目就这几句话:

有 $n$ 个物品,第 $i$ 个物品价值 $A _ {i}$ 元,现在问你 $q$ 次,从 $l$ 到 $r$ 中,最多能组合出多少种价值(**每个物品只能用一次**)?

这一看,这岂不是 01 背包 DP ?

01背包板子: $dp[i][j] = dp[i - 1][j - w[i]]$


仔细思考后发现,这题不能开 DP 数组!应该使用 `std::bitset` 优化!

不难发现, DP 数组的每个元素始终保持着存储 $0$ 或 $1$ ,就和二进制很像!而 `std::bitset` 则就是把他当成一个二进制数,自然空间会小很多。

我们每次就是要从上一个状态中推过来,所以 bitset 一个就够了,这算是滚动优化。

于是乎推出公式: `dp = dp | (dp << a[i]);`

最后,我们给 DP 数组加个前缀和即可!

在原 OJ 上已 AC !(在洛谷没绑号,可不是没 AC 发题解啊!)

```cpp
#include <bits/stdc++.h>
using namespace std;
int a[100007];
bitset<100007> dp;
int pr[100007]; // 前缀和
int n, q;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    // freopen(".in", "r", stdin);
    // freopen(".out", "w", stdout);
    cin >> n >> q;
    dp[0] = 1; // 很显然,0是一定拼的出来的。
    pr[0] = 1;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        dp |= dp << a[i]; // 公式,不再赘述。
    }
    for (int i = 1; i <= 100000; i++)
        pr[i] = pr[i - 1] + dp[i]; // 前缀和
    for (int i = 1; i <= q; i++)
    {
        int l, r;
        cin >> l >> r;
        cout << pr[r] - pr[l - 1] << '\n'; // 前缀和直接O(1)处理。
    }
    return 0;
}

原因:很遗憾,您的《题解:SP30738 ADACOINS - Ada and Coins》不符合推荐标准。原因是:上下标应使用abca _ {b} ^ {c}$a _ {b} ^ {c}$)进行表示。。

2025/2/8 10:25
加载中...