【单调队列】最大子序和

在这里插入图片描述
初步学习单调队列,
先从简单点的开始理解。

每次找出在(i-m,i)范围内的最小sum[j]值。

#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
ll sum[maxn];
list<int> lt;
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		lt.clear();
		sum[0]=0;
		for(int i=1;i<=n;i++){
			scanf("%lld",&sum[i]);
			sum[i]=sum[i-1]+sum[i];
		}
		ll maxs=sum[1];
		lt.push_front(1);
		for(int i=2;i<=n;i++){
			while(!lt.empty()&&i-lt.back()>m){
				lt.pop_back();
			}
			maxs=max(maxs,sum[i]-sum[lt.back()]);
			while(!lt.empty()&&sum[i]<sum[lt.front()]){
				lt.pop_front();
			}
			lt.push_front(i);
		}
		printf("%lld\n",maxs);
	}
	return 0;
}

初始化先用sum数组存储前缀和,
sum[i]-sum[j]这样就可以求出区间和了。
然后在第二个for循环里更新

因为题目要求是在m的范围内
所以每次进来先检测是否 i - 队列的末尾>m,

while(!lt.empty()&&i-lt.back()>m){
	lt.pop_back();
}

(为什么不是等于,因为前缀和数组的被减数是包含前面的)

之后更新最大值maxs。

maxs=max(maxs,sum[i]-sum[lt.back()]);

为了保证队列是从大到小,并且每次要求sum[j]尽可能小,所以,

while(!lt.empty()&&sum[i]<sum[lt.front()]){
	lt.pop_front();
}

如果队首的元素的sum比当前的sum[ j ] 大,那就pop掉,
因为当前的 i 又新它的sum又小 ,

最后

lt.push_front(i);

将i插入队首就好

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值