P1725 琪露諾 題解

FRZ_29發表於2024-08-10

思路

動態規劃,單調佇列

動態規劃

觀察題目,發現下標為 \(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幾天有思路今天才寫 */