小苯的序列分割1.0
[牛客链接](https://www.nowcoder.com/practice/24c59dfa375e4d01b83689dd8f471b4b)
题意
给定长度为 的序列
,将其划分为恰好
个非空的连续段,每段求和得到序列
。最大化:
$$
其中奇数位置 ,偶数位置
。
思路
把目标拆开看:
$$
因为所有 之和等于
(不管怎么分),所以第一项是定值。问题转化为最大化偶数位置段的总和
。
把 个段按奇偶交替排列:段 1(奇)、段 2(偶)、段 3(奇)……共
个偶数段。
用 DP 直接求解。定义 为前
个元素恰好分成
段时,偶数段元素之和的最大值(
是当前正在处理的元素)。
对于第 个元素(从第 2 个开始遍历),它可以:
- 延续当前第
段:
(+
若
是偶数)
- 开启新的第
段:
(+
若
是偶数)
取两者较大值:
$$
初始化 (第一个元素在第 1 段,奇数段,贡献 0),其余为
。为避免覆盖,
从大到小更新。
最终答案为 。
以样例 1 验证:,
,
。最优划分
得
,
,答案
。
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int T;
scanf("%d", &T);
while(T--){
int n, k;
scanf("%d%d", &n, &k);
vector<long long> a(n);
long long sumA = 0;
for(int i = 0; i < n; i++){
scanf("%lld", &a[i]);
sumA += a[i];
}
int m = k / 2;
if(m == 0){
printf("%lld\n", sumA);
continue;
}
const long long NEG_INF = -(long long)4e18;
vector<long long> dp(k + 1, NEG_INF);
dp[1] = 0;
for(int i = 1; i < n; i++){
for(int j = min(k, i + 1); j >= 1; j--){
long long best = dp[j];
if(j > 1 && dp[j-1] > NEG_INF)
best = max(best, dp[j-1]);
if(j % 2 == 0)
dp[j] = (best > NEG_INF) ? best + a[i] : NEG_INF;
else
dp[j] = best;
}
}
printf("%lld\n", sumA + dp[k]);
}
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));
StringBuilder sb = new StringBuilder();
int T = Integer.parseInt(br.readLine().trim());
while (T-- > 0) {
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
long[] a = new long[n];
long sumA = 0;
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
a[i] = Long.parseLong(st.nextToken());
sumA += a[i];
}
int m = k / 2;
if (m == 0) {
sb.append(sumA).append('\n');
continue;
}
final long NEG_INF = (long) -4e18;
long[] dp = new long[k + 1];
Arrays.fill(dp, NEG_INF);
dp[1] = 0;
for (int i = 1; i < n; i++) {
for (int j = Math.min(k, i + 1); j >= 1; j--) {
long best = dp[j];
if (j > 1 && dp[j - 1] > NEG_INF)
best = Math.max(best, dp[j - 1]);
if (j % 2 == 0)
dp[j] = (best > NEG_INF) ? best + a[i] : NEG_INF;
else
dp[j] = best;
}
}
sb.append(sumA + dp[k]).append('\n');
}
System.out.print(sb);
}
}
复杂度分析
- 时间复杂度:
。每个元素遍历时更新
个状态。
- 空间复杂度:
,DP 数组。

京公网安备 11010502036488号