描述
输入一个长度为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); }