Pagini recente » Cod sursa (job #276021) | Cod sursa (job #2009299) | Cod sursa (job #956714) | Cod sursa (job #430030) | Cod sursa (job #1749881)
/** 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;
}