Pagini recente » Borderou de evaluare (job #178082) | Borderou de evaluare (job #991010) | Borderou de evaluare (job #1369969) | Borderou de evaluare (job #1707939) | Cod sursa (job #1988293)
#include <vector>
#include <iostream>
#include <queue>
#include <set>
#include <cassert>
#include <limits>
#include <algorithm>
using namespace std;
#include <ext/pb_ds/detail/standard_policies.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree <
long long, // Key Type
null_type, // Mapped type
less<long long>, // Compare functor
rb_tree_tag, // Tree tag: [rb_tree_tag|splay_tree_tag|ov_tree_tag]
tree_order_statistics_node_update // Update policy
> ordered_set;
// Extra functions: find_by_order() and order_of_key()
template<typename T>
struct LinearFunSet {
vector<T> slopes, intercepts;
ordered_set fenwick;
int n;
LinearFunSet(vector<T> slopes) {
sort(slopes.begin(), slopes.end());
slopes.resize(unique(slopes.begin(), slopes.end()) - slopes.begin());
this->slopes = slopes;
n = slopes.size();
intercepts.resize(n, 123456789);
}
int find_by_order(int order) {
if (order < 0 or order >= fenwick.size())
return -1;
return *fenwick.find_by_order(order);
}
int get_pos(int slope) {
int ret = lower_bound(slopes.begin(), slopes.end(), slope)
- slopes.begin();
assert(slopes[ret] == slope);
return ret;
}
bool is_bad(int pos) {
if (pos == -1) return false;
int order = fenwick.order_of_key(pos);
int prv = find_by_order(order - 1);
int nxt = find_by_order(order + 1);
if (prv == -1 or nxt == -1) return false;
long long ad = (intercepts[pos] - intercepts[prv])
* (slopes[nxt] - slopes[pos]);
long long bc = (intercepts[pos] - intercepts[nxt])
* (slopes[prv] - slopes[pos]);
return ad <= bc;
}
void check_stack(int pos) {
if (is_bad(pos)) {
assert(fenwick.erase(pos));
return;
}
while (true) {
int order = fenwick.order_of_key(pos);
int prv = find_by_order(order - 1);
if (is_bad(prv)) {
assert(fenwick.erase(prv));
} else break;
}
while (true) {
int order = fenwick.order_of_key(pos);
int nxt = find_by_order(order + 1);
if (is_bad(nxt)) {
assert(fenwick.erase(nxt));
} else break;
}
}
T EvaluateMax(T x) {
int step;
T best = numeric_limits<T>::min();
int at = -1;
for (step = 1; step <= n; step *= 2);
for (step /= 2; step; step /= 2) {
int fun_id = find_by_order(at + step);
if (fun_id != -1) {
T now = slopes[fun_id] * x + intercepts[fun_id];
if (now >= best) {
best = now;
at += step;
}
}
}
return best;
}
void AddFunction(int slope, int intercept) {
int pos = get_pos(slope);
return;
intercepts[pos] = intercept;
check_stack(pos);
}
};
int main() {
freopen("euro.in", "r", stdin);
freopen("euro.out", "w", stdout);
int n, t;
cin >> n >> t;
vector<long long> gain(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> gain[i];
gain[i] += gain[i - 1];
}
// dp[i] = max_j(dp[j] + (gain[i] - gain[j]) * i - t)
// dp[i] = max_j(dp[j] - gain[j] * i + gain[i] * i - t)
// dp[i] = gain[i] * i - t + max_j(dp[j] - gain[j] * i)
// solution: keep stack of linear functions of type -gain[j] * X + dp[j]
// no monotony -> need set
for (auto &x : gain) x = -x;
LinearFunSet<long long> linear_set(gain);
for (auto &x : gain) x = -x;
long long ans = 0;
linear_set.AddFunction(0, 0);
for (int i = 1; i <= n; ++i) {
ans = linear_set.EvaluateMax(i) + gain[i] * i - t;
linear_set.AddFunction(-gain[i], ans);
}
cout << ans << endl;
return 0;
}