Cod sursa(job #1853787)

Utilizator RazvanR104Razvan-Andrei Ciocoiu RazvanR104 Data 22 ianuarie 2017 01:19:20
Problema Euro Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.46 kb
#include <bits/stdc++.h>

using namespace std;

typedef int64_t i64;

const int NMAX = 35000;
const long double inf = 1e30;
const long double eps = 1e-6;

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;
}

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];

struct Compare {
	bool operator()(const pair<long double, i64> &lhs, const pair<long double, i64> &rhs) const {
		if (getSign(lhs.first - rhs.first) < 0)
			return 1;
		if (getSign(lhs.first - rhs.first) > 0)
			return 0;
		return lhs.second < rhs.second;
	}
};

set<Line> convexHullTrick;
set<pair<long double, i64>, Compare> 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 (getSign(xzIntersect - xyIntersect) <= 0)
	if ((x->n - y->n) * (z->m - x->m) - (x->n - z->n) * (y->m - x->m) >= 0)
		return 1;
	return 0;
}

void Update(set<Line>::iterator y) {
	if (y == convexHullTrick.end())
		return;
	xIntervals.erase({X[y->pos], y->pos});
	if (y == convexHullTrick.begin()) {
		X[y->pos] = -inf;
		xIntervals.insert({X[y->pos], 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 x = prev(y), z = next(y);
	if (y != convexHullTrick.end() && y->m == z->m) {
		convexHullTrick.erase(y);
		return;
	}
	if (y != convexHullTrick.begin() && x->m == y->m) {
		if (Check(x)) {
			xIntervals.erase({X[x->pos], x->pos});
			convexHullTrick.erase(x);
			Update(y);
		} else {
			convexHullTrick.erase(y);
			return;
		}
	} else 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));
	}
	Update(y);
	Update(next(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;
	}

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

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

	return 0;
}