제출 #1288543

#제출 시각아이디문제언어결과실행 시간메모리
1288543harryleee수열 (APIO14_sequence)C++20
71 / 100
350 ms196608 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll NEG_INF = (ll)-9e18;
const ll INF = (ll)9e18;
const int MAXK = 205;
const int MAXN = 100000;

int n, k;
ll a[MAXN + 5];
ll pre[MAXN + 5];
int trace_pos[MAXN + 5][MAXK]; // trace_pos[i][c] = best t for dp[i][c]
ll dp[MAXN + 5][MAXK]; // dp[i][c] = min sumsq for prefix i into c parts

struct line {
    long long a, b;
    mutable long double p;
    int id;
    bool operator < (const line& other) const {
        if (other.a == (long long)1e18 && other.b == (long long)1e18)
            return p < other.p;
        return a < other.a || (a == other.a && b < other.b);
    }
};

struct LINE_CONTAINER {
    multiset<line> ms;
    inline bool del(multiset<line>::iterator x, multiset<line>::iterator y){
        if (y == ms.end()){
            x->p = 1e18;
            return false;
        }
        if (x->a == y->a){
            x->p = (x->b >= y->b) ? 1e18 : -1e18;
        } else {
            x->p = (long double)(y->b - x->b) / (long double)(x->a - y->a);
        }
        return x->p >= y->p;
    }
    inline void update(long long a, long long b, int i){
        auto x = ms.insert({a, b, 0.0L, i});
        auto y = next(x);
        while (del(x, y)) y = ms.erase(y);
        if (x != ms.begin()){
            y = prev(x);
            if (del(y, x)) ms.erase(x);
        } else y = x;
        while (y != ms.begin()){
            x = prev(y);
            if (del(x, y)){
                del(x, ms.erase(y));
                y = x;
            } else break;
        }
    }
    inline pair<long long,int> get(long long x){
        auto it = ms.lower_bound({(long long)1e18, (long long)1e18, (long double)x, 0});
        if (it == ms.end()) return {NEG_INF, 0};
        return { it->a * x + it->b, it->id };
    }
};

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    if (!(cin >> n >> k)) return 0;
    for (int i = 1; i <= n; ++i) { cin >> a[i]; pre[i] = pre[i-1] + a[i]; }
    // dp[0][0]=0, rest = INF
    for (int i = 0; i <= n; ++i)
        for (int c = 0; c <= k+1; ++c) {
            dp[i][c] = INF;
            trace_pos[i][c] = 0;
        }
    dp[0][0] = 0;

    // c = number of parts (1 .. k+1)
    for (int c = 1; c <= k+1; ++c){
        LINE_CONTAINER lc;
        // We want min_t (dp[t][c-1] + pre[t]^2 - 2*pre[i]*pre[t]).
        // To reuse max-CHT, store lines with a' = 2*pre[t], b' = -(dp[t][c-1] + pre[t]^2),
        // then max(a'*x + b') = - min(dp[t][c-1] + pre[t]^2 - 2*pre[t]*x).
        // So dp[i][c] = pre[i]^2 - max(...)  and trace = id of that line.
        // Insert line for t=0 first (if valid)
        if (dp[0][c-1] < INF/4) lc.update(2LL*pre[0], -(dp[0][c-1] + pre[0]*pre[0]), 0);

        for (int i = 1; i <= n; ++i){
            auto g = lc.get(pre[i]);
            if (g.first != NEG_INF){
                ll val = pre[i]*pre[i] - g.first; // dp[i][c]
                if (val < dp[i][c]){
                    dp[i][c] = val;
                    trace_pos[i][c] = g.second;
                }
            }
            // add line for t = i to be used for later i' > i
            if (dp[i][c-1] < INF/4){
                ll slope = 2LL * pre[i];
                ll intercept = -(dp[i][c-1] + pre[i]*pre[i]);
                lc.update(slope, intercept, i);
            }
        }
    }

    ll total = pre[n]*pre[n];
    ll min_sumsq = dp[n][k+1];
    ll best_points = (total - min_sumsq) / 2; // (S^2 - sum sq)/2
    cout << best_points << '\n';

    // reconstruct cuts: backtrack from (n, k+1)
    vector<int> cuts;
    int cur = n, c = k+1;
    while (c > 0 && cur > 0){
        int prev = trace_pos[cur][c];
        if (prev == 0) break;
        cuts.push_back(prev);
        cur = prev;
        --c;
    }
    reverse(cuts.begin(), cuts.end());
    // We need exactly k cut positions between 1 and n-1: cuts should contain k positions.
    // If cuts contains fewer (some prev were 0), fill none — but normally problem constraints guarantee a solution.
    for (size_t i = 0; i < cuts.size() && (int)i < k; ++i){
        if (i) cout << ' ';
        cout << cuts[i];
    }
    cout << '\n';
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...