第2题-加速窗口收益
小红书9月17日机考题目与解析
推理集群上排着 项作业,第 项有一个收益 (正数表示划算,负数表示亏本)。
调度允许开一次加速窗口:挑一段连续作业 (),把这段里每一项的收益改成原来的两倍。也可以一次都不开。
窗口用完之后(或者根本没用),再从作业序列里取出一段非空的连续作业,使它们的收益加起来尽量大。请给出这个最大和。
取出的那段至少要包含一项,不能交空段。
输入描述
首行给出正整数 (),即询问组数。
随后 行,每行先写出正整数 (),再跟 个整数 (),即该组作业条数和各项收益。
各组 加起来不超过 。
输出描述
一行输出 个整数,相邻两项用空格隔开,依次为每组询问的最大连续收益和。
样例 1
输入:
2
4 2 -3 4 -1
3 -5 -2 -7输出:
8 -2说明: - 第一组:把 (收益 )翻倍,序列变成 。最大连续和是单独的 。 - 第二组:全是负数,翻倍只会更亏,不开窗口,答案是最大的一项 。
样例 2
输入:
1
6 1 2 -5 3 -1 4输出:
12说明:把 ()翻倍,这段和从 变成 。左侧 接上去会变差,所以最大就是 。
思路
最大子段和变形。设最终取的答案段为 、窗口为 ,总收益 ;而 本身也是数组的一段连续子段,其和不会超过全局最大子段和,因此上界是 最大子段和,并且把窗口恰好开在最大子段上就能取到。
- 若最大子段和 (所有元素为负):翻倍只会更小,不开窗口,答案 = 最大元素;
- 否则:求最大子段和,答案 最大子段和。
两种写法等价:方法一是 Kadane 逐项转移;方法二用前缀和——最大子段和 。
代码
方法一:Kadane
t = int(input())
for _ in range(t):
arr = list(map(int, input().split()))[1:]
ans = max(arr)
if ans <= 0:
print(ans, end=' ')
continue
cur = arr[0]
for x in arr[1:]:
cur = max(x, cur + x)
ans = max(ans, cur)
print(ans * 2, end=' ')方法二:前缀和
t = int(input())
def solve():
a = list(map(int, input().split()))
a = a[1:]
pref = [0] * (len(a) + 1)
for i in range(1, len(a) + 1):
pref[i] = pref[i - 1] + a[i - 1]
mx = max(a)
mn = 0
for i in range(1, len(pref)):
mx = max(mx, pref[i] - mn)
mn = min(mn, pref[i])
mx = mx * 2 if mx >= 0 else mx
print(mx, end=' ')
for _ in range(t):
solve()第2题-加速窗口收益
https://mingsm17518.github.io/2026/11/03/刷题笔记/机考/小红书/2026年9月17日/第2题-加速窗口收益/