单调队列的板子题,维护好队首队尾,然后一路找最值过去。
维护的操作注释写在代码里了
int n, m;
ll sum[maxn], x, ans=-inf;
int q[maxn]; //q[]是队伍位置(下标)
int head=0, tail=1;
int main()
{
n = read();
m = read();
FOR(i, 1, n)
{
x = read();
sum[i] = sum[i-1] + x; //线性算出前缀和
}
FOR(i, 1, n)
{
while(head < tail && sum[i-1] <= sum[q[tail-1]])
tail--; //不断删除队尾直到队尾的sum小于当前sum,因为如果它比sum[i-1]大,又在i-1左边,那是没有意义的
while(head < tail && q[head] < i-m)
head++; //限制队内个数
//有意思的是当head==tail时,下一行的修改相当于同时修改队首队尾元素的赋值,
q[tail++] = i-1; //元素赋值,新队尾加入
ans = max(ans, sum[i]-sum[q[head]]);
//printf("i = %d ; head = %d ; tail = %d ; q[head] = %d ; ans = %lld\n", i, head, tail, q[head], ans);
}
cout<<ans;
return 0;
}