Submission #1173637

#TimeUsernameProblemLanguageResultExecution timeMemory
1173637ivazivaSplit the sequence (APIO14_sequence)C++20
0 / 100
3 ms4416 KiB
#pragma GCC optimize("Ofast,unroll-loops")
#include <bits/stdc++.h>

using namespace std;

#define MAXN 100001
#define MAXM 201
#define int long long
const int INF = LLONG_MAX;

struct LiChaoTree {
    struct Line {
        int m, b;
        Line(int _m = 0, int _b = -INF) : m(_m), b(_b) {}
        int eval(int x) { return m * x + b; }
    };

    vector<Line> tree;
    int minX, maxX, sz;

    LiChaoTree(int _minX, int _maxX) : minX(_minX), maxX(_maxX) {
        sz = 1;
        while (sz < (maxX - minX + 1)) sz *= 2;
        tree.assign(2 * sz, Line());
    }

    void addLine(Line newLine, int node = 1, int l = 0, int r = -1) {
        if (r == -1) r = sz - 1;
        int mid = (l + r) / 2;
        bool leftBetter = newLine.eval(l + minX) > tree[node].eval(l + minX);
        bool midBetter = newLine.eval(mid + minX) > tree[node].eval(mid + minX);
        
        if (midBetter) swap(tree[node], newLine);
        if (l == r) return;

        if (leftBetter != midBetter) addLine(newLine, 2 * node, l, mid);
        else addLine(newLine, 2 * node + 1, mid + 1, r);
    }

    int getMax(int x) {
        int pos = x - minX;
        int node = 1, l = 0, r = sz - 1;
        int best = -INF;
        
        while (true) {
            best = max(best, tree[node].eval(x));
            if (l == r) break;
            int mid = (l + r) / 2;
            if (pos <= mid) {
                node = 2 * node;
                r = mid;
            } else {
                node = 2 * node + 1;
                l = mid + 1;
            }
        }
        return best;
    }
};

int n, k;
int pref[MAXN], dp[2][MAXN];
vector<int> where[MAXM];

int32_t main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n >> k;
    pref[0] = 0;
    for (int i = 1; i <= n; i++) {
        cin >> pref[i];
        pref[i] += pref[i - 1];
    }

    for (int i = 1; i < n; i++)
        dp[0][i] = pref[i] * (pref[n] - pref[i]);

    for (int i = 0; i <= k; i++) where[i].resize(n, -1);

    for (int br = 2; br <= k; br++) {
        LiChaoTree tree(0, MAXN);
        for (int pos = br; pos < n; pos++) {
            tree.addLine({pref[pos - 1], dp[0][pos - 1] - pref[pos - 1] * pref[n]});
            dp[1][pos] = pref[pos] * (pref[n] - pref[pos]) + tree.getMax(pref[pos]);
        }
        for (int pos = br; pos < n; pos++)
            dp[0][pos] = dp[1][pos];
    }

    int maks = dp[0][k], pos = k;
    for (int i = k + 1; i < n; i++) {
        if (dp[0][i] > maks) {
            maks = dp[0][i];
            pos = i;
        }
    }

    cout << maks << endl;
    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...