算法竞赛进阶指南---0x12(队列)最大子序和

题面

在这里插入图片描述

题解

  1. 这其实是一道单调队列优化区间dp问题,对于这个序列,我们可以划分为n个区间,每个区间代表以ai结尾,长度不超过m的子序列和,我们只需要遍历一遍每个集合,找到每一个集合中的最大值,那么就可以更新出这个序列的最大值
  1. 如何找每个集合中的最大值呢,最大值就是要求出以a[k]结尾,长度不超过m的子序列和最大,求区区间和我们可以用前缀和,s[k]-s[k-j] (1<=j<=m) ,要想使所求值最大,那么就要使s[k-j]最小 ,所以问题就转化成求一个滑动区间的最小值问题,我们就可以用单调队列做优化

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 300010, INF = 0x3f3f3f3f;

int n, m;
int s[N], q[N];

int main() {
    
    

    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
    
    
        scanf("%d", &s[i]);
        s[i] += s[i - 1];
    }

    int res = -INF;
    int hh = 0, tt = 0;
    for (int i = 1; i <= n; i++) {
    
    
        if (q[hh] < i - m) hh++;
        res = max(res, s[i] - s[q[hh]]);
        while (hh <= tt && s[i] <= s[q[tt]]) tt--;
        q[++tt] = i;
    }

    printf("%d\n", res);


    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44791484/article/details/113935299