最大连续和(单调队列+前缀和)

题意

 思路

我们发现,如果从序列中某个元素A(i)开始向右构造子序列,其能组成的子序列为A(i),A(i)+A(i+1),……,A(i)+……+A(i+m-1),如果我们需要求从Ai开始的长度不超过m的各个非空子序列的值,每次都累加显然会有不小的时间负担,因此我们会考虑到使用前缀和,这时以A(i)+……+A(i+m-1)为例,其值就可以表示为前缀和(i+m-1)- 前缀和(i-1)。

接下来我们要求从A(i)开始向右构造子序列的所有子序列中的最大值,那我们就会发现,对于这些子序列,其实减数【前缀和(i-1)】是不变的,变的只是被减数【前缀和(i),前缀和(i+1),……,前缀和(i+m-1)】,求序列最大值,就可以转化为求被减数的最大值,而被减数的最大值,就是一个不超过m的区间里的前缀和的最大值,既然如此,我们就能想到滑动窗口,用单调队列来处理前缀和数组。

最后,只要比较以A(1),A(2),……,A(m)为开头的向右构造长度不超过m的子序列的最大值,找出他们的最大值,就是答案了。

代码

#include <iostream>
#include <queue> 
using namespace std;
typedef struct a{
	int index,num;
}a; 
const int maxn=2e5+5;
a arr[maxn];
int main(){
	deque<a>window;
	int n,m;
	cin>>n>>m;
	arr[0].num=0;
	for(int i=1;i<=n;i++){
		cin>>arr[i].num;
		arr[i].num+=arr[i-1].num;
		arr[i].index=i;
	}
	int ans=arr[1].num;
	for(int i=1;i<=n;i++){
		while(!window.empty()&&window.back().num<arr[i].num)window.pop_back();
		if(!window.empty()&&window.front().index<=i-m)window.pop_front();
		window.push_back(arr[i]);
		if(i-m>0){
			ans=max(ans,window.front().num-arr[i-m].num);
		}
		else{
			ans=max(ans,window.front().num-arr[0].num);
		}
	}
	for(int i=n-m+1;i<n;i++){
		while(!window.empty()&&window.front().index<=i)window.pop_front();
		ans=max(ans,window.front().num-arr[i].num);
	}
	cout<<ans;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值