📅  最后修改于: 2023-12-03 14:56:54.542000             🧑  作者: Mango
给定一个长度为n的整数数组a和一个非负整数k,每次操作可以将a数组中的一个区间[l, r]全部反转(即a[i]变成a[l+r-i])。求进行不超过k次操作后的最大前缀和。
考虑贪心,每次我们需要找到目前a数组中的最大值max。若max大于0,则操作区间[l, r]应该是包含max的,否则我们操作空区间。对于每个max都进行这样的操作,直到操作次数超过k或者不存在正数。
而在进行操作时,我们需要保留目前已经反转了多少数字,以便计算最大前缀和。注意到我们每次操作一段区间[l, r],会对[l-lmax, r+lmax]上的数字的顺序进行改变。因此,当我们完成一次操作后,需要将操作区间的端点更新为[l-lmax, r+lmax](其中lmax为目前反转的数字数量),并将最大前缀和更新为当前前缀和与[l-lmax, r+lmax]的最大前缀和之和。
def max_prefix_sum(a, k):
"""
a: List[int],长度为n的整数数组
k: int,非负整数,表示可以进行的操作次数
return: int,进行不超过k次操作后的最大前缀和
"""
n = len(a) # 数组长度
l = 0 # 最大值所在区间的左端点(包含)
r = 0 # 最大值所在区间的右端点(包含)
lmax = 0 # 已经反转了的数字数量
ans = 0 # 最大前缀和
while k > 0 and l < n: # 当还可以进行操作且还未遍历数组
# 找到目前a数组中的最大值max
while r < n and (r <= l or a[r] <= 0):
r += 1
if r >= n: # 已经没有正数
break
max_index = r
for i in range(r+1, n):
if a[i] > a[max_index]:
max_index = i
if a[max_index] > 0:
break
max_value = a[max_index]
# 计算操作区间[l, r]和[l-lmax, r+lmax]
left = max(l, max_index-lmax)
right = min(r, max_index+lmax)
left_rev = n - right - 1
right_rev = n - left - 1
# 反转[l, r]
for i in range((l+max_index)//2, max_index):
a[i], a[l+max_index-i] = a[l+max_index-i], a[i]
lmax += right-max_index+1
# 反转[l-lmax, r+lmax]
for i in range((left+right)//2, right+1):
a[i], a[left+right-i] = a[left+right-i], a[i]
lmax += right_rev-right
# 更新区间[l, r]和前缀和
l = left_rev
r = right_rev
ans = max(ans, sum(a[l:right+1])+sum(a[left:right+1]))
k -= 1
return ans