1201 最大子序和 (单调队列)

描述

输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。

例如 1,-3,5,1,-2,3

当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6

输入格式

第一行两个数n,m(n,m<=300000)
第二行有n个数,要求在n个数找到最大子序和

输出格式

一个数,数出他们的最大子序和

样例输入

6 4
1 -3 5 1 -2 3

样例输出

7

思路:对于区间和转化为前缀和相减的形式,即使得sum【i】 - sum【j】最大 (i > j && i - j <= m)
贪心思想:用一个队列(数组也ok)存储可用的左节点j,开始时队列只有一个0(sum【0】 == 0),并且最左边的就是最优的节点(也就是sum【j】以递增顺序,j保存到队列中)
当队列中最左端的节点j < i-m时出栈,对于当且节点i,也加入队列,但是要将队列中sum【j】 >= sum【i】的节点j全部出队(因为对于i后面的的节点选择最小的sum【j】,且节点越靠后越好,该节点存活越久)


(可以数组实现)
#include<bits/stdc++.h>
using namespace std;

deque<int>que;
const int maxn = 3e5+5;
int n,m;
int sum[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        int tmp;
        scanf("%d",&tmp);
        sum[i] = sum[i-1] + tmp;
    }
    que.push_back(0);
    int ans = -INT_MAX;
    for(int i=1;i<=n;i++)
    {
        if(!que.empty() && que.front() < i-m)que.pop_front();
        ans = max(ans,sum[i] - sum[que.front()]);
        while(!que.empty() && sum[que.back()] >= sum[i])que.pop_back();
        que.push_back(i);
    }
    printf("%d
",ans);
}
View Code


原文地址:https://www.cnblogs.com/iwannabe/p/10632900.html