题目传送门
#include <bits/stdc++.h>
using namespace std;
const int N = 300010;
const int INF = 0x3f3f3f3f;
int n, m;
int q[N]; //单调队列,记录的是1~n
int s[N]; //前缀和数组
int main() {
//优化输入
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> s[i], s[i] += s[i - 1];
//首先需要明确滑动窗口的含义和范围
//含义: 在当前节点i时,记录着离节点i最近的m个节点的min(前缀和)。如果不足m的,那有多少算多少。
//范围: 为了让序号为1的节点,也能找到它对应的互动窗口,好走一样的逻辑,所以窗口中需要初始化一个0
//单调队列初始化:tt=0
//解释:因为求前缀和可能需要用到s[0]。例如选第一个数,就是s[1]-s[0]
//因此需要将s[0]也加入单调队列中,所以这里tt=0,也就是默认加入一个s[0]了。
int hh = 0, tt = 0;
int res = -INF;
for (int i = 1; i <= n; i++) {//讨论右边界
//窗口长度大于m,剪短窗口
if (q[hh] < i - m)hh++;
//Q:为什么不是 q[hh] < i - m + 1 啊 长度m不是可以取到吗
//A:因为滑动窗口处理的是i前面的不包括i的长度为m的最小值s[j],这个时候s[i]还没进窗口呢
//队列是单调的,所以,队列头是最小的
//更新区间最大值
res = max(res, s[i] - s[q[hh]]);
//位置i准备入队列
while (hh <= tt && s[q[tt]] >= s[i]) tt--;//单调队列出队
//单调队列中记录的是序号,真正用值的时候,需要s[q[hh]]
q[++tt] = i;
}
//输出结果
printf("%d", res);
return 0;
}