最大子序和(单调队列)
题目链接
题目
输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。
题解
单调队列维护的是 下标位置递增,对应的前缀和S也递增 。
分为以下三个步骤:
- 判断队头与i距离是否超过m,超过则弹出;
- 更新ans答案,此时左端点一定是 满足条件的下标最小且前缀和最小的位置 ;
- 删除不符合条件的队尾,把i作为新决策入队。
所谓的不符合条件,就是指如果存在 k<=j,并且sum[k]>=sum[j] ,那么这个k就可以舍去了。
代码
ll n,m,a[maxn],p[maxn],sum[maxn];
ll ans;
int main()
{
read(n),read(m);
for(int i=1;i<=n;i++) {
read(a[i]);
sum[i] = sum[i-1]+a[i];
}
int l=1,r=1;
for(int i=1;i<=n;i++) {
while(l<=r&&p[l]+m<i) l++;
ans = max(ans,sum[i]-sum[p[l]]);
while(l<=r&&sum[p[r]]>=sum[i]) r--;
p[++r] = i;
}
cout<<ans<<endl;
return 0;
}