为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接:P1405
题目描述
小红拿到了一个数组,她希望进行最多一次操作: 将一个元素修改为 X X X。小红想知道,最终的连续子数组最大和最大是多少?
输入描述
第一行输入一个正整数
t
t
t,代表询问次数。
对于每次询问,输入两行:
第一行输入两个正整数
n
n
n和
x
x
x。代表数组的大小,以及小红可以修改成的元素。
第二行输入 n n n个正整数 a i a_i ai,代表小红拿到的数组。
1 ≤ t ≤ 100000 1 \leq t \leq 100000 1≤t≤100000
1 ≤ n ≤ 200000 1 \leq n \leq 200000 1≤n≤200000
− 1 0 9 ≤ x , a 1 ≤ 1 0 9 -10^9 \leq x,a_1 \leq 10^9 −109≤x,a1≤109
每组所有询问的 n n n的和不超过 200000 200000 200000。
输出描述
输出t行,每行输出一个整数,代表连续子数组的最大和。
样例
输入
3
5 10
5 -1 -5 -3 2
2 -3
-5 -2
6 10
4 -2 -11 -1 4 -1
输出
15
-2
15
提示
第一组询问,修改第二个数。
第二组询问,不进行任何修改。
第三组询问,修改第三个数。
思路
step1:不带修改
如果不带修改,那么就是朴素的最大子段和。经典dp
step2:带修改
某个位置改成 x x x之后,我们要考虑的是必须包含这个位置的最大子段和。那么也就是左边一段(可以为空)拼上 x x x再拼上右边一段(可以为空),如下图所示
容易发现, A A A 必须是以 a i − 1 a_{i-1} ai−1 结尾的最大子段和。 B B B必须是以 a i + 1 a_{i+1} ai+1 为开头的最大子段和。
证明:反证法
令 A A A是以 a i a_i ai为结尾的最大子段和。
假设存在一个更大的 A ′ > A A' > A A′>A 。由于 A ′ A' A′也是以 a i a_i ai 为结尾的子段。可以推出 A A A 并不是最大子段和,和假设冲突。
所以 A A A 一定要是最大子段和
所以做法就是:正着求一遍最大子段和 d p dp dp,反着求一遍最大子段和 f f f。
答案为:不修改的最大子段和 与 枚举每个位置尝试修改的最大子段和 , 两者的最大值
对于前者,答案就是 m a x ( d p ) max(dp) max(dp)
对于后者的第 i i i 个位置 , m a x ( d p ( i − 1 ) , 0 ) + x + m a x ( f ( i + 1 , 0 ) ) max(dp(i-1) , 0)+x+max(f(i+1 , 0)) max(dp(i−1),0)+x+max(f(i+1,0))
注意,对 0 0 0 取最大值是代表左右两个段可以为空
代码
def read_input():
# Read the number of test cases
t = int(input())
# Iterate over each test case
test_cases = []
for i in range(t):
# Read the input for the current test case
n, x = map(int, input().split())
a = list(map(int, input().split()))
test_cases.append((n, x, a))
return test_cases
def calculate_dp(n, a):
# Initialize the dp array
dp = [0] * (n + 2)
# Calculate the dp array
for j in range(1, n + 1):
dp[j] = max(dp[j - 1], 0) + a[j - 1]
return dp
def calculate_f(n, a):
# Initialize the f array
f = [0] * (n + 2)
# Calculate the f array
for j in range(n, 0, -1):
f[j] = max(f[j + 1], 0) + a[j - 1]
return f
def calculate_ans(n, x, a, dp, f):
# Initialize the answer
ans = 0
# Calculate the answer
# Case 1: Do not modify any value
ans = max(dp[1:n + 1])
# Case 2: Modify each value and check the maximum subarray sum
for j in range(1, n + 1):
ans = max(ans, x + max(dp[j - 1], 0) + max(f[j + 1], 0))
return ans
def solve_test_cases(test_cases):
# Iterate over each test case
for n, x, a in test_cases:
# Calculate the dp array
dp = calculate_dp(n, a)
# Calculate the f array
f = calculate_f(n, a)
# Calculate the answer
ans = calculate_ans(n, x, a, dp, f)
# Print the answer for the current test case
print(ans)
test_cases = read_input()
solve_test_cases(test_cases)