TYVJ 1305最大子序和【单调队列】

单调队列:即一个具有单调性的队列,可以递增也可以递减。它的思想是在队列中及时排除一定不是最优解的选择,

题目描述:给定一个长度为N的整数序列(可能有负数),从中找出一段长度不超过M的连续子序列,使得子序列中所有数的和最大。N,M<=3*10^5。

分析:我们先求出前缀和,则连续子序列 [L,R] 中数的和就等于 S[R] - S[L-1]。所以原问题就转换为:找出两个位置 x,y,使得

S[y] - S[x] 最大并且 y - x <= M。

首先我们枚举右端点 i ,当 i 固定时, 问题就变为:找到一个左端点 j,i - M <= j <= i -1 ,并且s[j]最小。

我们可以用一个队列来保存这个序列。从左往右扫描右端点,对每个i执行以下三个步骤: 
1.判断当前队头的数与 i 的距离是否大于M,若超出则出队。
2.此时队头就是右端点为i时的最佳答案(不是最佳的答案在每次第三步更新sum[i]进队的时候都出队了) 
3.不断删除队尾直到队尾的s值小于s[i](因为如果一个s值比s[i]大,他的位置又比i靠左,那么他是没有存在意义的),将s[i]入队; 

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int maxn=300000+7;
int a[maxn],sum[maxn];
int n,m;
int q[maxn];
int main(){
	scanf("%d %d", &n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		sum[i]=sum[i-1]+a[i];
	}
	int l=1,r=1;
	q[1]=0;
	int ans=0;
	for(int i = 1; i <= n; i++){
		while(l <= r&&q[l] < i-m) l++;
		ans=max(ans,sum[i]-sum[q[l]]);
		while(l<=r&&sum[q[r]]>=sum[i]) r--;
		q[++r] = i;
	}
	printf("%d\n",ans);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值