其他分享
首页 > 其他分享> > AcWing 135. 最大子序和

AcWing 135. 最大子序和

作者:互联网

题目传送门

#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;
}

标签:前缀,int,tt,节点,队列,135,子序,单调,AcWing
来源: https://www.cnblogs.com/littlehb/p/15801560.html