洛谷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;
}
posted @ 2026-09-18 10:52  quanjun  阅读(6)  评论(0)    收藏  举报