最大子序和
508.最大子序和
本题使用 单调队列的思想来 求最大子序和 一道模板题
我们要求区间和,一般转化为两个前缀和相减。我们求出
s
[
i
]
s[i]
s[i](前i项的和)
,要求
[
L
,
R
]
[L,R]
[L,R]的最大的区间和就变成了找到两个x, y, 使得
s
[
y
]
−
s
[
x
]
s[y] - s[x]
s[y]−s[x]最大并且
y
−
x
<
=
m
y - x <= m
y−x<=m, 我们枚举区间右端点
i
i
i,寻找区间左端点
j
j
j , 在$[i - m,i] $ 中,使得s[j]最小, 这样我们得到的区间和最大, 可以发现此时这个序列必须保持单调递增的性质,才能有最大值,所以就可以用单调队列来写。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10, INF = -2e9;
int a[N], q[N];
signed main()
{
int n, m;
scanf("%lld %lld", &n, &m);
for(int i = 1; i <= n;i ++ )
{
scanf("%lld", &a[i]);
a[i] += a[i - 1]; //处理前缀和
}
int ans = INF;
int l = 0, r = 0;
for(int i = 1; i <= n; i ++ )
{
if(l <= r && q[l] < i - m) l ++;
//如果已经出了左端点的范围就右移队头,使得队头一直在寻找的区间内
//因为每次队头最多只会移一位,所以用 if,这里用 while 也对
ans = max(ans, a[i] - a[q[l]]); //求最大子序和
while(l <= r && a[q[r]] >= a[i]) r --;
q[++ r] = i;//把元素的下标插入队列中
}
printf("%lld", ans);
return 0;
}