제출 #102891

#제출 시각아이디문제언어결과실행 시간메모리
102891beobeoSplit the sequence (APIO14_sequence)C++14
0 / 100
330 ms5044 KiB
/* Problem URL: https://oj.uz/problem/view/APIO14_sequence
   Tags: dp, convex hull optimization */

#include <iostream>
#include <vector>
#include <deque>
#include <stack>
#include <algorithm>

using namespace std;

const int N = 100005;

long long a[N];

struct Line {
    long long a, b;
    int idx;

    long long GetCost(long long x) {
        return a * (x - a) + b;
    }

    long long To(Line& rhs) {
        long long lo = max(a, rhs.a);
        long long hi = 1LL << 60;

        while (lo < hi) {
            long long mid = (lo + hi) / 2;
            long long v1 = GetCost(mid);
            long long v2 = rhs.GetCost(mid);

            if (v1 <= v2) {
                hi = mid;
            }
            else {
                lo = mid + 1;
            }
        }
        return hi;
    }
};

bool Check(Line& l1, Line& l2, Line& l3) {
    return 1.0 * (l3.b - l1.b) * (l1.a - l2.a) > 1.0 * (l2.b - l1.b) * (l1.a - l3.a);
}

int main() {
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    vector<long long> sums(n + 1);
    for (int i = 0; i < n; i++) {
        sums[i + 1] = sums[i] + a[i];
    }

    vector<long long> dp1(n + 1);
    vector<long long> dp2(n + 1);
    vector<vector<int>> splits(k, vector<int>(n + 1));
    for (int i = 0; i < k; i++) {
        deque<Line> lines;
        for (int j = 0; j <= n; j++) {
            while (lines.size() > 1 && lines[0].GetCost(sums[j]) <= lines[1].GetCost(sums[j])) {
                lines.pop_front();
            }

            if (!lines.empty()) {
                dp2[j] = lines[0].GetCost(sums[j]);
                splits[i][j] = lines[0].idx;
            }

            Line l({sums[j], dp1[j], j});
            // while (lines.size() > 1 && Check(lines[lines.size() - 2], lines[lines.size() - 1], l)) {
            //     lines.pop_back();
            // }

            while (lines.size() > 1) {
                long long t1 = lines[lines.size() - 2].To(lines[lines.size() - 1]);
                long long t2 = lines[lines.size() - 1].To(l);

                if (t1 >= t2) break;
                else lines.pop_back();
            }
            lines.push_back(l);
        }

        dp1 = dp2;
    }

    cout << dp2[n] << endl;
    stack<int> st;
    for (int i = k - 1, j = n; i >= 0; i--) {
        j = splits[i][j];
        st.push(j);
    }

    while (!st.empty()) {
        cout << st.top() << ' ';
        st.pop();
    }
}
#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...