给定长度为 的序列 , 从中选出 个 不相交区间, 从左到右记它们的和为 ,
请最大化下述合式
表示前 个数, 组成 个区间, 的最优值
表示 选择 第 个数, , 最优值,
表示 选择或不选择 第 个数, , 最优值,
即 表示当前数比两边都小时的情况, 只会对答案造成 负贡献.
表示 选择 第 个数, , 最优值,
表示 选择或不选择 第 个数, , 最优值.
即 表示当前数比两边都大时的情况, 只会对答案造成 正贡献.
则
紫色部分为
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define reg register int
#define rep(i, a, b) for (reg i = a; i <= b; i++)
const int INF = 1e9, N = 30005, K = 205;
const double eps = 1e-6, phi = acos(-1.0);
ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
int f[N][K][4];
int main() {
freopen("optimization.in", "r", stdin);
freopen("optimization.out", "w", stdout);
int n = read(), k = read();
rep(i, 1, k) rep(j, 0, 3) f[0][i][j] = -INF;
rep(i, 1, n) {
int x = read();
rep(j, 1, k) {
int flag = 2 - (j == 1 || j == k);
f[i][j][0] = max(f[i - 1][j][0], f[i - 1][j - 1][3]) - flag * x;//low
f[i][j][1] = max(f[i - 1][j][1], f[i][j][0]);//
f[i][j][2] = max(f[i - 1][j][2], f[i - 1][j - 1][1]) + flag * x;//high
f[i][j][3] = max(f[i - 1][j][3], f[i][j][2]);
if (flag - 1) {
f[i][j][1] = max(f[i][j][1], f[i - 1][j - 1][1]);
f[i][j][3] = max(f[i][j][3], f[i - 1][j - 1][3]);
}
}
}
printf("%d
", max(f[n][k][1], f[n][k][3]));
}