思路:
1.集合划分(求分别以每个元素结尾的不超过m长度的最大连续子序和)
2.求以每个元素结尾状态的最大值
集合:dp[i]以i为右端点,长度不超过m的区间
属性:连续子区间的最大值
状态转移:dp[i]=s[i]-min(s[j]) (j-m<=j<=i-1)==>m-1
(要看的最大范围是i元素前面的一个m窗口,加上i元素一共m+1个元素,因为区间和(k,i)的公式为s[i]-s[k-1])
#include<iostream>
#include<algorithm>
using namespace std;
const int N=3e5+10;
const int INF=1e9;
int a[N];
int s[N];
int q[N];
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
int res=-INF;
int tt=0,hh=0;//此处的tt是从0开始,代表队列中已经有了一个元素
for(int i=1;i<=n;i++) {
if(i-m>q[hh]) hh++;//维持窗口大小注意此处i-m不用加一
res=max(res,s[i]-s[q[hh]]);//该队列不包含当前元素
while(tt>=hh&&s[i]<=s[q[tt]]) tt--;
q[++tt]=i;
}
cout<<res;
return 0;
}