Cod sursa(job #1749881)

Utilizator depevladVlad Dumitru-Popescu depevlad Data 29 august 2016 01:39:00
Problema Euro Scor 100
Compilator cpp Status done
Runda Lista lui wefgef Marime 3.51 kb
/** Thank you a_h1926 for a very nice learning experience about dynamic lower envelopes. 
    Cheers!
*/

#include <cstdio>
#include <algorithm>
#include <set>

using namespace std;

const int kMaxN = 35000;
const double kEps = 1e-9;
const double kInf = 1e16;
const double kQuerySlope = -1e30;

class Line {
  public:
    double n, m;
    mutable double x;
    Line(const double _m, const double _n) : m(_m), n(_n), x(kInf) {}
    double Ordinate(double x) const { return m * x + n; }
    inline bool operator <(Line const& other) const {
      if(fabs(other.m - kQuerySlope) < kEps) return x - other.n < -kEps; /// (Workaround) If this is a query, apply the query comparator (sort by intersection).
      if(fabs(m - other.m) < kEps) return n - other.n > kEps; /// In case of equality, sort by offset.
      return m - other.m < -kEps; /// Sort by slope.
    }
};

class LowerEnvelope : public multiset<Line> {
  public:
    void Insert(Line const& line) {
      iterator p = insert(line);
      if(notValid(p)) { /// Test if the starting state is invalid.
        erase(p);
        return;
      }
      while(p != begin() && notValid(prev(p))) erase(prev(p)); /// Trim left while state is invalid.
      while(next(p) != end() && notValid(next(p))) erase(next(p)); /// Trim right while state is invalid.
      if(p != begin()) Update(prev(p)); /// Update the intersection point of the previous line.
      Update(p); /// Update the intersection point of the current line.
    }
    double Query(double x) { /// Finds the line corresponding to x, evaluates it and returns the result.
      Line q_line(kQuerySlope, x); /// Simulate a line. Workaround for lower_bound.
      iterator p = lower_bound(q_line); /// The position.
      return p->Ordinate(x); /// Evaluate the line.
    }
  private:
    bool notValid(iterator m) {
      if(m == end()) return false; /// The set is empty, and the state automatically valid.
      iterator r = next(m);
      if(m == begin()) { /// If the current element is the first
        if(r == end()) return false; /// The set contains only one element, and the state is correct.
        return fabs(m->m - r->m) < kEps && m->n - r->n < kEps; /// The only way the state would be invalid would be if the two lines are equal.
      }
      iterator l = prev(m);
      if(r == end())  /// If the current element is the last
        return fabs(m->m - l->m) < kEps && m->n - l->n < kEps; /// Either same slope, but lower offset, or equal.
      return (m->n - l->n) * (m->m - r->m) - (l->m - m->m) * (r->n - m->n) > -kEps; /// The position is in the middle, and the normal algorithm applies. Test if Cross(l, m) <= Cross(m, r).
    }
    void Update(iterator p) {
      if(p == end()) return; /// Handle this unlikely case.
      iterator r = next(p);
      if(r == end()) p->x = kInf; /// There is no next line, assign INF to the intersection.
      else p->x = (r->n - p->n) / (p->m - r->m); /// Calculate the intersection.
    }
};

inline int64_t Round(double x) { /// Rounds a given double to the nearest int64.
  return int64_t(x + 0.5);
}

int main() {
  freopen("euro.in", "r", stdin);
  freopen("euro.out", "w", stdout);
  
  int n, t;
  int64_t s = 0, dyn_prog = 0;
  
  LowerEnvelope env; 
  env.insert(Line(0, 0));
  
  scanf("%d %d", &n, &t);
  for(int i = 1; i <= n; i++) {
    int v;
    scanf("%d", &v);
    s += v;
    dyn_prog = Round(env.Query(i)) + s * i - t;
    env.Insert(Line(-s, dyn_prog));
  }
  
  printf("%lld\n", dyn_prog);
  return 0;
}