连续子数组最大和
[题目链接](https://www.nowcoder.com/practice/3e35a0679ec94df69e7db3b6e6bbf8fd)
思路
本题是经典"最大子数组和"(Kadane 算法)的变体:允许最多将一个元素替换为给定值 ,求连续子数组的最大和。
状态定义
用两个变量滚动更新即可,无需开数组:
:以当前位置结尾的最大子数组和,未做任何替换;
:以当前位置结尾的最大子数组和,恰好替换了一个元素。
转移方程
对于位置 :
$$
含义与标准 Kadane 完全一致——要么从当前位置重新开始,要么延续之前的子数组。
$$
三种情况分别对应:
- 只选当前位置,且把它替换为
:子数组长度为 1;
- 把当前位置替换为
,接在之前未替换的子数组后面:之前没用过替换机会,在这里用掉;
- 保留当前位置,接在之前已替换过的子数组后面:替换机会已经在前面用掉了,当前位置保持原值。
答案
全局答案取所有位置的 的最大值,因为可以选择不替换(取
)或替换一个(取
)。
初始化
$$
初始为
,表示把第一个元素替换为
。
样例演示
第一组:,
。
把 替换为
,子数组
和为
?不,最优是把
替换为
,子数组
。DP 过程会自动找到这个最优方案。
复杂度
- 时间复杂度:
,每组询问线性扫描一次。
- 空间复杂度:
,用于存储输入数组(DP 本身只用
额外空间)。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
long long p;
scanf("%d%lld",&n,&p);
vector<long long> a(n);
for(int i=0;i<n;i++) scanf("%lld",&a[i]);
long long dp0=a[0], dp1=p;
long long ans=max(dp0,dp1);
for(int i=1;i<n;i++){
long long ndp0=max(a[i], dp0+a[i]);
long long ndp1=max({p, dp0+p, dp1+a[i]});
dp0=ndp0;
dp1=ndp1;
ans=max({ans,dp0,dp1});
}
printf("%lld\n",ans);
}
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine().trim());
StringBuilder sb = new StringBuilder();
while (T-- > 0) {
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
long p = Long.parseLong(st.nextToken());
st = new StringTokenizer(br.readLine());
long[] a = new long[n];
for (int i = 0; i < n; i++) a[i] = Long.parseLong(st.nextToken());
long dp0 = a[0], dp1 = p;
long ans = Math.max(dp0, dp1);
for (int i = 1; i < n; i++) {
long ndp0 = Math.max(a[i], dp0 + a[i]);
long ndp1 = Math.max(p, Math.max(dp0 + p, dp1 + a[i]));
dp0 = ndp0;
dp1 = ndp1;
ans = Math.max(ans, Math.max(dp0, dp1));
}
sb.append(ans).append('\n');
}
System.out.print(sb);
}
}
import sys
input = sys.stdin.readline
T = int(input())
out = []
for _ in range(T):
line1 = input().split()
n, p = int(line1[0]), int(line1[1])
a = list(map(int, input().split()))
dp0 = a[0]
dp1 = p
ans = max(dp0, dp1)
for i in range(1, n):
ndp0 = max(a[i], dp0 + a[i])
ndp1 = max(p, dp0 + p, dp1 + a[i])
dp0 = ndp0
dp1 = ndp1
if dp0 > ans:
ans = dp0
if dp1 > ans:
ans = dp1
out.append(ans)
print('\n'.join(map(str, out)))
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
const lines = [];
rl.on('line', line => lines.push(line.trim()));
rl.on('close', () => {
let idx = 0;
let T = parseInt(lines[idx++]);
const res = [];
while (T-- > 0) {
const parts = lines[idx++].split(' ');
const n = parseInt(parts[0]);
const p = BigInt(parts[1]);
const a = lines[idx++].split(' ').map(x => BigInt(x));
let dp0 = a[0], dp1 = p;
let ans = dp0 > dp1 ? dp0 : dp1;
for (let i = 1; i < n; i++) {
const ndp0 = a[i] > dp0 + a[i] ? a[i] : dp0 + a[i];
let ndp1 = p;
if (dp0 + p > ndp1) ndp1 = dp0 + p;
if (dp1 + a[i] > ndp1) ndp1 = dp1 + a[i];
dp0 = ndp0;
dp1 = ndp1;
if (dp0 > ans) ans = dp0;
if (dp1 > ans) ans = dp1;
}
res.push(ans.toString());
}
console.log(res.join('\n'));
});

京公网安备 11010502036488号