Cod sursa(job #1988273)

Utilizator retrogradLucian Bicsi retrograd Data 2 iunie 2017 16:09:06
Problema Euro Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.97 kb
#include <vector>
#include <iostream>
#include <queue>
#include <set>
#include <cassert>
#include <limits>
#include <algorithm>

using namespace std;

#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace __gnu_pbds;
 
typedef tree <
   long long, // Key Type
   null_type, // Mapped type
   less<long long>, // Compare functor
   rb_tree_tag, // Tree tag: [rb_tree_tag|splay_tree_tag|ov_tree_tag]
   tree_order_statistics_node_update // Update policy
> ordered_set;

// Extra functions: find_by_order() and order_of_key()

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

    LinearFunSet(vector<T> slopes) { 
        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 find_by_order(int order) {
        if (order < 0 or order >= fenwick.size())
            return -1;
        return *fenwick.find_by_order(order);
    }

    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 = find_by_order(order - 1);
        int nxt = 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 = 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 = 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 = 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);
            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;
}