제출 #1288575

#제출 시각아이디문제언어결과실행 시간메모리
1288575harryleee수열 (APIO14_sequence)C++20
0 / 100
1 ms348 KiB
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll NEG = LLONG_MIN / 4;

struct Line {
    ll m; // slope
    ll b; // intercept
    int id; // index that produced this line
    Line(ll _m=0, ll _b=0, int _id=0): m(_m), b(_b), id(_id) {}
};

bool bad(const Line &l1, const Line &l2, const Line &l3){
    // check if l2 is unnecessary between l1 and l3
    // (b3 - b1) / (m1 - m3) <= (b2 - b1) / (m1 - m2)
    // cross multiply, use __int128 to avoid overflow
    __int128 left  = (__int128)(l3.b - l1.b) * (__int128)(l1.m - l2.m);
    __int128 right = (__int128)(l2.b - l1.b) * (__int128)(l1.m - l3.m);
    return left <= right;
}

struct CHT {
    vector<Line> hull;
    int ptr = 0; // pointer for queries with increasing x

    void clear(){ hull.clear(); ptr = 0; }

    void add(Line L){ // slopes must be non-decreasing
        while(hull.size() >= 2 && bad(hull[hull.size()-2], hull.back(), L))
            hull.pop_back();
        hull.push_back(L);
        if (ptr >= (int)hull.size()) ptr = hull.size() - 1;
    }

    // query for maximum at x; x queries must be non-decreasing across calls
    pair<ll,int> query(ll x){
        if (hull.empty()) return {NEG, 0};
        while(ptr + 1 < (int)hull.size()){
            __int128 v1 = (__int128)hull[ptr].m * x + (__int128)hull[ptr].b;
            __int128 v2 = (__int128)hull[ptr+1].m * x + (__int128)hull[ptr+1].b;
            if (v2 >= v1) ++ptr;
            else break;
        }
        ll val = (ll)((__int128)hull[ptr].m * x + (__int128)hull[ptr].b);
        return {val, hull[ptr].id};
    }
};

// build and return CHT hull for level (K-1) using items i = 1..upto
// (we follow the same insertion rule as original: when computing dp_j at layer j, we insert into lc[j] only if j < K)
CHT build_lc_last(const vector<ll> &pre, int n, int K, int upto){
    // K is the current k we want to query for (so we want lc[K-1] with lines from dp_{K-1})
    vector<CHT> lc(K+1); // indices 0..K
    lc[0].add(Line(0, 0, 0)); // base
    for (int i = 1; i <= upto; ++i){
        int mxj = min(i, K);
        // iterate j desc to avoid using newly inserted lines in same i
        for (int j = mxj; j >= 1; --j){
            auto g = lc[j-1].query(pre[i] - pre[n]);
            if (g.first == NEG) continue;
            ll dp = g.first + pre[i] * (pre[n] - pre[i]);
            if (j < K) lc[j].add(Line(pre[i], dp, i));
        }
    }
    // return copy of lc[K-1]
    return lc[K-1];
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, k;
    if (!(cin >> n >> k)) return 0;
    vector<ll> a(n+1);
    vector<ll> pre(n+1, 0);
    for (int i = 1; i <= n; ++i){
        cin >> a[i];
        pre[i] = pre[i-1] + a[i];
    }

    ll res = NEG;
    int bestPos = 0;

    // initial full run to find best result and bestPos
    vector<CHT> lc(k+1);
    lc[0].add(Line(0, 0, 0));
    for (int i = 1; i <= n; ++i){
        int mxj = min(i, k);
        for (int j = mxj; j >= 1; --j){
            auto g = lc[j-1].query(pre[i] - pre[n]);
            if (g.first == NEG) continue;
            ll dp = g.first + pre[i] * (pre[n] - pre[i]);
            if (j < k) lc[j].add(Line(pre[i], dp, i));
            if (j == k && i < n && dp > res){
                res = dp;
                bestPos = i;
            }
        }
    }

    if (res == NEG) {
        // If there's no valid splitting (edge cases), print something reasonable:
        // Depending on problem, could be 0 and no cuts; here print 0 and nothing.
        cout << 0 << "\n";
        return 0;
    }

    cout << res << "\n";

    // reconstruct cuts by recomputing hulls up to bestPos-1 for each step
    vector<int> cuts;
    int rem = k;
    int curPos = bestPos;
    while (rem > 0 && curPos > 0){
        cuts.push_back(curPos);
        // build hulls up to level rem-1 using items up to curPos-1
        if (rem == 0) break;
        CHT ch = build_lc_last(pre, n, rem, curPos - 1);
        // query ch at x = pre[curPos] - pre[n] to get predecessor id
        auto g = ch.query(pre[curPos] - pre[n]);
        int prev = g.second; // might be 0 (base)
        curPos = prev;
        --rem;
    }

    reverse(cuts.begin(), cuts.end());
    for (int i = 0; i < (int)cuts.size(); ++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...