Cod sursa(job #1853286)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 21 ianuarie 2017 16:12:46
Problema Euro Scor 85
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.25 kb
#include <bits/stdc++.h>

using namespace std;

typedef int64_t i64;

const int NMAX = 35000;
const i64 inf = 1e18;
const long double eps = 1e-12;

int N, T;
int curr;
i64 sum[NMAX];
i64 DP[NMAX];
long double X[NMAX];

int getSign(long double value) {
	if (value >= -eps && value <= eps)
		return 0;
	if (value < -eps)
		return -1;
	return 1;
}

i64 doubleToInt(long double value) {
	int sgn = getSign(value);
	if (sgn == 0)
		return 0;
	if (sgn > 0)
		return value + 0.5;
	return value - 0.5;
}

struct Line {
	i64 m, n;
	int pos;
	Line(i64 m = 0, i64 n = 0, int pos = 0):
		m(m), n(n), pos(pos) {
	}
	bool operator<(const Line &rhs) const {
		return m < rhs.m ? 1 : (m > rhs.m ? 0 : n < rhs.n);
	}
	long double xIntersect(const Line &rhs) const {
		if (m == rhs.m)
			return inf;
		return (long double)(rhs.n - n) / (long double)(m - rhs.m);
	}
	i64 getValue(int x) {
		return m * x + n;
	}
} Lines[NMAX];

set<Line> convexHullTrick;
set<pair<long double, i64>> xIntervals;

bool Check(set<Line>::iterator y) {
	set<Line>::iterator x = prev(y), z = next(y);
	if (y == convexHullTrick.begin() || z == convexHullTrick.end())
		return 0;
	i64 xyIntersect = x->xIntersect(*y);
	i64 xzIntersect = x->xIntersect(*z);
	if (xzIntersect <= xyIntersect)
		return 1;
	return 0;
}

void Update(set<Line>::iterator y) {
	xIntervals.erase({X[y->pos], y->pos});
	if (y == convexHullTrick.begin()) {
		X[y->pos] = -inf;
		xIntervals.insert({-inf, y->pos});
	} else {
		set<Line>::iterator x = prev(y);
		X[y->pos] = x->xIntersect(*y);
		xIntervals.insert({X[y->pos], y->pos});
	}
}

void addLine(i64 m, i64 n) {
	Lines[curr] = Line(m, n, curr);
	set<Line>::iterator y = convexHullTrick.insert(Lines[curr++]).first;
	set<Line>::iterator z = next(y);
	if (z != convexHullTrick.end() && y->m == z->m) {
		convexHullTrick.erase(y);
		return;
	}
	set<Line>::iterator x = prev(y);
	if (y != convexHullTrick.begin() && x->m == y->m) {
		xIntervals.erase({X[x->pos], x->pos});
		convexHullTrick.erase(x);
		Update(y);
	}
	if (Check(y)) {
		convexHullTrick.erase(y);
		return;
	}
	while (next(y) != convexHullTrick.end() && Check(next(y))) {
		xIntervals.erase({X[next(y)->pos], next(y)->pos});
		convexHullTrick.erase(next(y));
	}
	while (y != convexHullTrick.begin() && Check(prev(y))) {
		xIntervals.erase({X[prev(y)->pos], prev(y)->pos});
		convexHullTrick.erase(prev(y));
	}
	if (next(y) != convexHullTrick.end())
		Update(next(y));
	Update(y);
}

int main() {
	assert(freopen("euro.in", "r", stdin));
	assert(freopen("euro.out", "w", stdout));

	int i;

	cin >> N >> T;
	for (i = 1; i <= N; ++i) {
		int value;
		cin >> value;
		sum[i] = sum[i - 1] + value;
	}

	for (i = 1; i <= N; ++i) {
		set<pair<long double, i64>>::iterator it = xIntervals.lower_bound({i, -inf});
		int lineIndex = -1;
		if (xIntervals.size()) {
			if (it == xIntervals.end()) {
				--it;
				lineIndex = it->second;
			} else if (i == it->first) {
				lineIndex = it->second;
			} else {
				--it;
				lineIndex = it->second;
			}
		}
		DP[i] = sum[i] * i - T;
		if (lineIndex != -1)
			DP[i] = max(DP[i], Lines[lineIndex].getValue(i) + sum[i] * i - T);
		addLine(-sum[i], DP[i]);
	}

	cout << DP[N] << '\n';

	return 0;
}