Cod sursa(job #1971113)

Utilizator tudi98Cozma Tudor tudi98 Data 19 aprilie 2017 20:29:52
Problema Euro Scor 95
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.61 kb
#include <bits/stdc++.h>
using namespace std;

#define REP(i,a) for (int i = 0; i < a; i++)
#define FOR(i,a,b) for (int i = a; i <= b; i++)
#define ROF(i,a,b) for (int i = a; i >= b; i--)
#define FOREACH(it,x) for (auto it: (x))
#define SZ(x) ((int)(x).size())
#define ll long long
#define iter set<Line>::iterator

const ll inf = 1LL<<60;

struct Line {
    ll a,b,val;
    bool is_query;
    double xlo;
    Line(ll _a,ll _b,ll _val,bool _is_query): a(_a),b(_b),is_query(_is_query),val(_val),xlo(-inf) {}

    bool operator<(Line Other) const {
        if (Other.is_query)
            return xlo - Other.val < -0.00000001;
        if (a == Other.a)
            return b < Other.b;
        return a < Other.a;
    }

    double intersect(Line Other) const {
        return 1.0 * (Other.b - b) / (a - Other.a);
    }
};

class HullTrick {
public:
    HullTrick() {}
    void Insert(Line l) {
        iter it = hull.insert(l).first;
        if (useless(it)) {
            hull.erase(it);
            return;
        }
        iter it1 = it,it2 = it;
        while (has_prev(it1) && useless(--it1)) hull.erase(it1++);
        while (has_next(it2) && useless(++it2)) hull.erase(it2--);
        if (has_prev(it)) update_left_border(it);
        if (has_next(it)) update_left_border(++it);
    }
    ll Query(ll x) {
        Line l = Line(0,0,x,true);
        iter it = hull.lower_bound(l);
        --it;
        return it->a * x + it->b;
    }

private:
    set<Line> hull;
    inline bool has_prev(iter it) const {
        return it != hull.begin();
    }
    inline bool has_next(iter it) const {
        return (it != hull.end()) && (++it != hull.end());
    }
    bool useless(iter it) const {
        if (!has_next(it) || !has_prev(it))
            return false;
        iter next = it, prev = it;
        next++; prev--;
        return prev->intersect(*next) <= prev->intersect(*it);
    }
    void update_left_border(iter it) {
        if (!has_prev(it)) return;
        iter prev = it; --prev;
        double where = it->intersect(*prev);
        Line l(*it);
        l.xlo = where;
        hull.erase(it++);
        hull.insert(it,l);
    }
};

HullTrick ht;
ll sum[35000];
ll B[35000];

int main()
{
    ifstream fin("euro.in");
    ofstream fout("euro.out");

    int n; ll T;
    fin >> n >> T;
    sum[0] = 0;
    ht.Insert(Line(0,0,0,false));
    FOR(i,1,n) {
        fin >> sum[i]; sum[i] += sum[i-1];
        if (i == 1) B[i] = sum[i] - T;
        else B[i] = ht.Query(i) + sum[i] * i - T;
        ht.Insert(Line(-sum[i],B[i],0,false));
    }
    fout << B[n];
}