Cod sursa(job #1988256)

Utilizator retrogradLucian Bicsi retrograd Data 2 iunie 2017 15:55:11
Problema Euro Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.64 kb
#include <vector>
#include <iostream>
#include <queue>
#include <set>
#include <cassert>
#include <limits>

using namespace std;

struct FenwickTreeSet {
    vector<int> fenwick;
    vector<bool> exists;

    int n, max_step;

    FenwickTreeSet(int n) :
        fenwick(n + 1, 0), exists(n, false), n(n) {
        for (max_step = 1; max_step <= n; max_step *= 2);
    }
    
    int order_of_key(int pos) {
        int ret = -1;
        for (++pos; pos > 0; pos -= (pos & -pos))
            ret += fenwick[pos];
        return ret;
    }

    bool insert(int pos)  {
        if (exists[pos]) return false;
        exists[pos] = true;

        for (++pos; pos <= n; pos += (pos & -pos))
            fenwick[pos] += 1;
        return true;
    }
    bool erase(int pos) {
        if (!exists[pos]) return false;
        exists[pos] = false;

        for (++pos; pos <= n; pos += (pos & -pos))
            fenwick[pos] -= 1;
        return true;
    }

    int find_by_order(int k) {
        if (k < 0) return -1;

        int ret = 0;
        for (int step = max_step; step; step /= 2) {
            if (ret + step <= n && fenwick[ret + step] <= k) {
                k -= fenwick[ret + step];
                ret += step;
            }
        }

        if (ret == n)
            return -1;
        return ret;
    }
};

template<typename T>
struct LinearFunSet {
    vector<T> slopes, intercepts;
    FenwickTreeSet fenwick;
    int n;

    LinearFunSet(vector<T> slopes) : fenwick(slopes.size()) { 
        sort(slopes.begin(), slopes.end());
        slopes.resize(unique(slopes.begin(), slopes.end()) - slopes.begin());
        this->slopes = slopes;

        n = slopes.size();
        intercepts.resize(n, 123456789);
    }

    int get_pos(int slope) {
        int ret = lower_bound(slopes.begin(), slopes.end(), slope)
            - slopes.begin();
        assert(slopes[ret] == slope);
        return ret;
    }

    bool is_bad(int pos) {
        if (pos == -1) return false;
        int order = fenwick.order_of_key(pos);
        int prv = fenwick.find_by_order(order - 1);
        int nxt = fenwick.find_by_order(order + 1);
        if (prv == -1 or nxt == -1) return false;

        long long ad = (intercepts[pos] - intercepts[prv]) 
                     * (slopes[nxt] - slopes[pos]);
        long long bc = (intercepts[pos] - intercepts[nxt]) 
                     * (slopes[prv] - slopes[pos]);

        return ad >= bc;
    }
  
    
    void check_stack(int pos) {
        if (is_bad(pos)) { 
            assert(fenwick.erase(pos));
            return;
        }

        while (true) {
            int order = fenwick.order_of_key(pos);
            int prv = fenwick.find_by_order(order - 1);
            if (is_bad(prv)) {
                assert(fenwick.erase(prv));
            } else break;
        }

        while (true) {
            int order = fenwick.order_of_key(pos);
            int nxt = fenwick.find_by_order(order + 1);
            if (is_bad(nxt)) {
                assert(fenwick.erase(nxt));
            } else break;
        }

    }

    T EvaluateMax(T x) {
        int step;
        T best = numeric_limits<T>::min();
  
        int at = -1;
        for (step = 1; step <= n; step *= 2);
        for (step /= 2; step; step /= 2) {
            int fun_id = fenwick.find_by_order(at + step);
            if (fun_id != -1) {
                T now = slopes[fun_id] * x + intercepts[fun_id];
                if (now >= best) {
                    best = now;
                    at += step;
                }
            }
        }
        return best;
    }

    void AddFunction(int slope, int intercept) {
        int pos = get_pos(slope);
        if (!fenwick.insert(pos) and intercepts[pos] >= intercept)
            return;

        intercepts[pos] = intercept;
        check_stack(pos);
    }
};

int main() {
    freopen("euro.in", "r", stdin);
    freopen("euro.out", "w", stdout);
    
    int n, t;
    cin >> n >> t;

    vector<long long> gain(n + 1);
    for (int i = 1; i <= n; ++i) {
        cin >> gain[i];
        gain[i] += gain[i - 1];
    }

    // dp[i] = max_j(dp[j] + (gain[i] - gain[j]) * i - t)
    // dp[i] = max_j(dp[j] - gain[j] * i + gain[i] * i - t)
    // dp[i] = gain[i] * i - t + max_j(dp[j] - gain[j] * i)
    // solution: keep "stack" of linear functions of type -gain[j] * X + dp[j]
    // no monotony -> need set
    
    for (auto &x : gain) x = -x;
    LinearFunSet<long long> linear_set(gain);
    for (auto &x : gain) x = -x;

    long long ans = 0;

    linear_set.AddFunction(0, 0);
    for (int i = 1; i <= n; ++i) {
        ans = linear_set.EvaluateMax(i) + gain[i] * i - t;
        linear_set.AddFunction(-gain[i], ans);
    }

    cout << ans << endl;


    return 0;
}