《算法竞赛进阶指南》最大子序和

最大子序和

输入一个长度为n的整数序列,从中找出一段长度不超过m的连续子序列,使得子序列中所有数的和最大。

注意: 子序列的长度至少是1。

输入格式
第一行输入两个整数n,m。

第二行输入n个数,代表长度为n的整数序列。

同一行数之间用空格隔开。

输出格式
输出一个整数,代表该序列的最大子序和。

数据范围
1≤n,m≤300000
输入样例:
6 4
1 -3 5 1 -2 3
输出样例:
7

求取自序和(或子串和)我们首先想到的是利用前缀和数组求取,当我们利用前缀和数组可以求取最大的一个自序和,但不能保证该最大自序和的长度;因此我们此时需要动态维护一个最大为m的数组来存储当前位置前m个的前缀和,并且我们还要能很快的找到其中的最小值;

这就引出了我们今天要用到的知识点“单调队列”,我们每次移动一位时,通过维护单调队列,使其满足其中所有的元素到达当前位置不超过m(我们只需要保持队首满足就行),另外我们要寻找当前能找到的最小值,即要维护一个单调递增队列,这样我们维护队列的时间复杂度是O(n)的查找时间复杂度是O(1)的;

#include<iostream>
#include<algorithm>
#include<limits.h>
using namespace std;
const int N=300010;
int n,m;
int s[N],q[N];//s数组用于存储前缀和
//q数组用于动态维护最多m长度的单调队列
//q数组存储的是s数组中的位置 
int main()
{
      ios::sync_with_stdio(false);
	  cin>>n>>m;
	  for(int i=1;i<=n;i++)
	  {  //建立前缀和数组 
	  	cin>>s[i];
	  	s[i]+=s[i-1];
	  }	
      int res=INT_MIN;//求取数值的最大值,初始值设置为最小值
	  int tt=0,hh=0;//tt为动态数组的队尾,hh为动态数组的队头
	  //该动态数组存储的位置可以对应到s数组中形成单调递增数组 
	  //这样队首才是当前能找到的最小值 
	  for(int i=1;i<=n;i++)
	  {
        if(q[hh]<i-m)hh++;//该动态数组中的队首存储的位置与i的距离
		//相差超过m时,此时要维护该动态数组的大小
		res=max(res,s[i]-s[q[hh]]);
		//正因为维护的是单调递增队列因此当前所能找到的最大
		//子串和为s[i]-s[q[hh]]
		while(hh<=tt&&s[i]<s[q[tt]])tt--;
		//维护使该动态数组保持单调递增性
		q[++tt]=i;//动态数组将当前位置入队  	
	  } 
	  cout<<res<<endl;
	  return 0;
} 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值