Submission #1356079

#TimeUsernameProblemLanguageResultExecution timeMemory
1356079cnam9Discharging (NOI20_discharging)C++20
100 / 100
487 ms736484 KiB
#include <iostream>
#include <stack>
#include <algorithm>

using namespace std;

template <class Value, size_t MAX_SIZE>
class BufferedStack {
    Value buf[MAX_SIZE];
    Value *end = buf;

public:
    inline bool empty() const { return end == buf; }

    inline void push(const Value &value) { *++end = value; }
    inline void pop() { --end; }

    inline Value top() const { return *end; }
};

constexpr int N = 1e6 + 5;
constexpr int INF = 1e9 + 67;
int n;
int a[N];
BufferedStack<int, N> stk;
pair<int, int> tree[N];

namespace CHT {
    int card;
    struct Ray {
        int stop;
        int a;
        long long b;
    };

    stack<Ray> hull[N];
    stack<tuple<int, int, int>> history;

    void init() {
        card = 1;
        hull[0].push(Ray{INF, INF, 0});
    }

    void insert(int a, long long b) {
        // cout << "inserts y = " << a << "x + " << b << endl;

        int low = min(1, card - 1);
        int high = card - 1;

        auto intersection = [&](const int i) {
            return a == hull[i].top().a ? n
                : clamp((b - hull[i].top().b) / (hull[i].top().a - a), 0ll, (long long) n);
        };

        while (low < high) {
            int mid = (low + high + 1) / 2;

            if (intersection(mid) >= hull[mid - 1].top().stop + 1) {
                low = mid;
            } else {
                high = mid - 1;
            }
        }

        history.emplace(card, low, hull[low].top().stop);
        hull[low].top().stop = intersection(low);
        hull[low + 1].push(Ray{INF, a, b});
        card = low + 2;
    }

    long long query(int x) {
        int low = 0;
        int high = card - 1;

        while (low < high) {
            int mid = (low + high) / 2;
            if (x <= hull[mid].top().stop) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        long long res = (long long) hull[low].top().a * x + hull[low].top().b;
        // cout << "query " << x << " -> " << res << endl;
        return res;
    }

    void undo() {
        auto [oldcard, low, stop] = history.top();
        history.pop();

        hull[low].top().stop = stop;
        hull[low + 1].pop();
        card = oldcard;

        // cout << "undo" << endl;
    }
}

long long dnc(int l, int r, int m) {
    if (l >= r) {
        if (l == n) {
            cout << CHT::query(l);
            exit(0);
        }
        return l ? CHT::query(l) : 0;
    }
    long long b = dnc(l, m, tree[m].first);
    // cout << "[" << l << ", " << m << "] -> [" << m + 1 << ", " << r << "]" << endl;
    CHT::insert(a[m], b);
    b = min(b, dnc(m + 1, r, tree[m].second));
    CHT::undo();
    return b;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    // freopen("input.txt", "r", stdin);

    cin >> n;

    a[n] = INF;
    stk.push(n);
    for (int i = n - 1; i >= 0; i--) {
        cin >> a[i];

        tree[i].second = -1;
        while (a[stk.top()] < a[i]) {
            tree[i].second = stk.top();
            stk.pop();
        }
        tree[stk.top()].first = i;
        stk.push(i);
    }

    CHT::init();
    dnc(0, n, tree[n].first);

    return 0;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...