洛谷P3648 [APIO2014] 序列分割 题解 斜率优化DP
题目链接:https://www.luogu.com.cn/problem/P3648
解题思路:完全来自 hongzy大佬的博客
差别:没有使用滚动数组~
对于 \(X\) 相同的点,取 \(Y\) 大的,同时维护上凸包。
一开始用 C++17提交 TLE 了两个点,然后改成 C++ 23 提交就 AC 了~
示例程序:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 5;
int n, K, pre[maxn][201], que[maxn];
ll s[maxn], f[maxn][201], g[maxn];
void output(int p, int k) {
int q = pre[p][k];
if (k > 1) output(q, k-1);
assert(q >= 1 && q < n);
printf("%d ", q);
}
inline ll X(int i) { return s[i]; }
inline ll Y(int i) { return g[i]; }
inline double slope(int a, int b) {
if (X(a) == X(b))
return (Y(b) > Y(a)) ? 1e18 : -1e18;
return 1.0 * (Y(b) - Y(a)) / (X(b) - X(a));
}
int main() {
scanf("%d%d", &n, &K);
for (int i = 1, a; i <= n; i++) {
scanf("%d", &a);
s[i] = s[i-1] + a;
}
for (int k = 1; k <= K; k++) {
for (int i = k; i <= n; i++)
g[i] = f[i][k-1] - s[i] * s[i];
int l = 1, r = 0;
for (int i = k+1; i <= n; i++) {
if (l <= r && X(que[r]) == X(i-1)) {
r--;
}
while (l < r && slope(que[r-1], que[r]) <= slope(que[r], i-1))
r--;
que[++r] = i-1;
while (l < r && slope(que[l], que[l+1]) >= -s[i])
l++;
int j = que[l];
f[i][k] = f[j][k-1] + s[j] * (s[i] - s[j]);
pre[i][k] = j;
}
}
printf("%lld\n", f[n][K]);
output(n, K);
return 0;
}
浙公网安备 33010602011771号