题意

选择长度在 1..m1..m 之间的非空连续子段,使元素和最大。

思路

prefix[i] 为前 ii 项和。固定右端前缀 i 时,合法左端前缀 j 位于 [i-m,i-1],子段和是 prefix[i]-prefix[j]。因此只需维护这个滑动窗口内最小的前缀和。

递增单调队列保存候选前缀;先删除过期队头并计算答案,再把当前前缀作为未来候选加入。

Python 知识

  • 不保存完整前缀数组,只用变量 prefix 在线累加。
  • 两个紧凑数组分别保存候选下标与前缀值,适合五十万规模。
  • 流式整数解析同时支持负数并控制内存。

代码

python
import os
from array import array


def read_ints():
    number = 0
    sign = 1
    reading = False
    while chunk := os.read(0, 1 << 20):
        for byte in chunk:
            if 48 <= byte <= 57:
                number = number * 10 + byte - 48
                reading = True
            else:
                if reading:
                    yield sign * number
                    number = 0
                    sign = 1
                    reading = False
                elif byte == 45:
                    sign = -1
    if reading:
        yield sign * number


data = iter(read_ints())
n, limit = next(data), next(data)
queue_index = array("i", [0]) * (n + 1)
queue_value = array("q", [0]) * (n + 1)
head, tail = 0, 1
prefix = 0
answer = -10**30

for i in range(1, n + 1):
    prefix += next(data)
    while head < tail and queue_index[head] < i - limit:
        head += 1
    answer = max(answer, prefix - queue_value[head])
    while head < tail and queue_value[tail - 1] >= prefix:
        tail -= 1
    queue_index[tail] = i
    queue_value[tail] = prefix
    tail += 1

print(answer)

复杂度

时间复杂度 O(n)O(n),空间复杂度 O(n)O(n)

总结

限长最大子段和等价于“当前前缀减最近窗口内最小前缀”。