好的,我将这道题整理为清晰的题面格式,并补充样例解释、数据范围与时空限制:
题目描述
给你一个长度为 n 的整数序列 {A1,A2,…,An},要求从中找出一段 连续的长度不超过 m 的子序列,使得这个序列的和最大。
输入格式
第一行为两个整数 n,m;
第二行为 n 个用空格分开的整数,表示 A1,A2,…,An,每个数的绝对值都小于 1000。
输出格式
仅一个整数,表示连续长度不超过 m 的最大子序列和。
样例
样例输入
6 4
1 -3 5 1 -2 3
样例输出
7
样例解释
数组:[1,−3,5,1,−2,3],m=4。
需要找长度不超过 4 的连续子序列,使和最大。
考虑所有长度不超过 4 的连续子序列:
- 长度 1:最大为 5(子序列 [5])
- 长度 2:[5,1] 和为 6
- 长度 3:[5,1,−2] 和为 4
- 长度 4:[5,1,−2,3] 和为 7
因此最大和为 7,对应子序列 [5,1,−2,3](长度 4)。
数据范围
- 对于 50% 的数据,1≤N,M≤104;
- 对于 100% 的数据,1≤N,M≤2×105。
时空限制
- 时间:1000 ms
- 内存:524288 KB
提示
此题为 最大子段和 的变种,增加了长度不超过 m 的限制。
方法:
设 Si=A1+A2+⋯+Ai(前缀和)。
则子段 [j+1,i] 的和为 Si−Sj,要求 i−j≤m,即 j≥i−m。
问题转化为:对于每个 i,求 Si−minj∈[i−m,i−1]Sj 的最大值,其中 j≥0(若 j=0 表示取前缀和 S0=0)。
因此可以用 单调队列 维护区间 [i−m,i−1] 内 Sj 的最小值。
步骤:
- 计算前缀和 S[0…n],S[0]=0;
- 维护一个单调递增队列(队首存储最小的 Sj 对应的下标);
- 遍历 i 从 1 到 n:
- 如果队首下标 qfront<i−m,则弹出队首(因为超出窗口范围);
- 用 Si−S[qfront] 更新答案;
- 从队尾弹出所有 S[qback]≥Si 的下标(因为 Si 更小且更靠后,比它们更优);
- 将 i 入队。
注意:初始化时,先将 S0=0 的下标 0 入队,然后从 i=1 开始遍历。
复杂度:O(n)。
示例(样例):
- S=[0,1,−2,3,4,2,5]
- m=4
- 单调队列维护最小前缀和,遍历得到最大差值 7。