SCUT - 365 - 鹏哥的数字集合 - 斜率优化dp

https://scut.online/p/365

写这篇的时候还不是很明白,看一下这个东西。https://www.luogu.org/problemnew/solution/P2365

胡大佬的标程

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int MAXN = 300010;
ll dp[MAXN], a[MAXN], n, m, cnt[MAXN], que[MAXN];

ll X(int i, int j) {
    return a[j + 1] - a[i + 1];
}

ll Y(int i, int j) {
    return (dp[j] + a[j + 1] * a[j + 1]) - (dp[i] + a[i + 1] * a[i + 1]);
}

ll DP(int i, int j) {
    return dp[j] + (a[i] - a[j + 1]) * (a[i] - a[j + 1]);
}

ll solve(ll C) {
    dp[0] = 0;
    cnt[0] = 0;
    int s = 0, t = 0;
    que[++t] = 0;
    for(int i = 1; i <= n; i++) {
        while(s + 1 < t && Y(que[s + 1], que[s + 2]) < 2LL * a[i] * X(que[s + 1], que[s + 2]))
            s++;
        dp[i] = DP(i, que[s + 1]) + C;
        cnt[i] = cnt[que[s + 1]] + 1;
        while(s + 1 < t && 1LL * Y(que[t], i) * X(que[t - 1], que[t]) <= 1LL * Y(que[t - 1], que[t]) * X(que[t], i))
            t--;
        que[++t] = i;
    }
    return cnt[n];
}

int main() {
    scanf("%lld%lld", &n, &m);
    for(int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    sort(a + 1, a + 1 + n);
    ll l = 0, r = 1e12;
    while(l < r) {
        int mid = (l + r) >> 1;
        int tmp = solve(mid);
        if(tmp <= m)
            r = mid;
        else
            l = mid + 1;
    }
    solve(r);
    printf("%lld\n", dp[n] - m * r);
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/11318830.html
365