P1725 琪露诺 题解

题目传送门

思路

动态规划,单调队列

动态规划

观察题目,发现下标为 \(i\) 的点只能对 \([i + l, i + r]\) 区间的点产生贡献。

\(f_i\) 为到达点 \(i\) 时的最大冻结指数。

易得状态转移方程式:\(f_k \leftarrow \max(f_k, f_i+a_k),(k \in [i + l, i + r])\)

若直接对该方程进行转移,时间复杂度是 \(O(n^2)\) 的,会爆。虽然数据水放过去了。

单调队列

考虑优化,对题目给出的条件进行转化,发现能对 \(i\) 产生贡献的,只有 \([i - r, i - l]\) 区间的点。

又因为 \(f_i\) 为到达点 \(i\) 时的最大冻结指数,所以产生贡献的点是明确的,即 \([i - r, i - l]\) 区间中最大值,这恰好又是一个滑动窗口,自然能用单调队列优化。

细节

  1. 在一些数据中,有一些点是无法到达的,比如这个: 5 3 4 0 1 2 3 4 5
    下标为 \(5\) 的点是无法到达的,而如果维护单调队列时 \(f_1\)\(0\) 的话,\(f_5\) 会为 \(5\)
    所以应该把 \(f\) 数组初始化为负无穷的。

  2. 最后统计答案时只要统计 \([n + 1 - r, n]\) 的区间内的即可。

  3. 统计答案时要预先把答案制成负无穷。

代码

点击查看代码
/*
  --------------------------------
  |        code by FRZ_29        |
  |          code  time          |
  |          2024/08/10          |
  |           08:16:15           |
  |             星期六            |
  --------------------------------
                                  */

#include <iostream>
#include <cstdio>
#include <deque>

using namespace std;

void RD() {}
template<typename T, typename... U> void RD(T &x, U&... arg) {
    x = 0; int f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    x *= f; RD(arg...);
}

const int N = 2e5 + 5, inf = -2e9;

#define PB push_back
#define PPB pop_back
#define PPF pop_front
#define LF(i, __l, __r) for (int i = __l; i <= __r; i++)
#define RF(i, __r, __l) for (int i = __r; i >= __l; i--)

int n, l, r, ans = inf;
int f[N], a[N];
deque<int> deq;

int main() {
    RD(n, l, r);
    LF(i, 0, n) RD(a[i]);
    deq.PB(0);

    LF(i, 1, n) f[i] = inf;

    LF(i, l, n) {
        while (deq.size() && i - r > deq.front()) deq.PPF();
        // printf("deq.front = %d\n", deq.front());
        f[i] = f[deq.front()] + a[i];
        while (deq.size() && f[i - l + 1] > f[deq.back()]) deq.PPB();
        deq.PB(i - l + 1);
        // printf("f[%d] = %d\n", i, f[i]);
    }

    // LF(i, 0, n) printf("f[%d] = %d ", i, f[i]);
    // puts("");
    LF(i, n + 1 - r, n) ans = max(ans, f[i]);
    printf("%d\n", ans);
    return 0;
}

/* ps:FRZ弱爆了,10几天有思路今天才写 */

当你的情人已改名玛丽,你怎能送她一首菩萨蛮?

posted @ 2024-08-10 09:15  FRZ_29  阅读(3)  评论(0编辑  收藏  举报