135 最大子序和(单调队列优化)

本文介绍了一种解决最优化问题的方法,即找出长度不超过m的连续整数序列,使得序列和最大。通过预处理前缀和并利用单调队列,可以有效地在O(n)时间内找到最大子序列和。代码示例展示了如何实现这个算法,适用于数据范围在1到300000之间的大规模问题。
摘要由CSDN通过智能技术生成

1. 问题描述:

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

输入格式

第一行输入两个整数 n,m。第二行输入 n 个数,代表长度为 n 的整数序列。同一行数之间用空格隔开。

输出格式

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

数据范围

1 ≤ n,m ≤ 300000

输入样例:

6 4
1 -3 5 1 -2 3

输出样例:

7
来源:https://www.acwing.com/problem/content/description/137/

2. 思路分析:

分析题目可以知道我们需要求解一段长度小于等于m的区间和,并且这一段区间在所有长度小于等于m的区间中的区间和是最大的,所以这是一个最优化的问题,我们可以枚举以i为右端点,在左边找一个长度小于等于m的左端点使得区间和是最大的,枚举所有的左端点那么一定可以找到一个长度小于等于m的区间和是最大的,在枚举右端点的过程中其实是维护一个长度小于等于m的区间所以可以使用单调队列来优化(本质上是求解长度的m的滑动窗口的最值问题==>单调队列优化),在队列中维护一个单调递增的队列即可,可以先预处理前缀和然后在枚举右端点的时候维护最小的前缀和信息即可,队头元素就是区间和最小的位置。

 

3. 代码如下:

if __name__ == "__main__":
     n, m = map(int, input().split())
     w = list(map(int, input().split()))
     s = [0]
     # 预处理前缀和
     for i in range(1, n + 1):
          s.append(s[-1] + w[i - 1])
     q = [0] * (n + 1)
     # 一开始的时候s[0]为队列中的一个元素所以tt = 0
     hh, tt = 0, 0
     res = -10 ** 9
     for i in range(1, n + 1):
          # 不包含第i个位置(通过画图来确定边界)
          if hh <= tt and q[hh] < i - m: hh += 1
          # 更新答案: 当前位置的前缀和减去最小的前缀和那么得到的就是以当前位置结尾的前缀和的最大值
          res = max(res, s[i] - s[q[hh]])
          # 单调队列维护窗口长度小于等于m的最小前缀和的位置
          while hh <= tt and s[q[tt]] >= s[i]: tt -= 1
          tt += 1
          q[tt] = i
     print(res)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值