Commando
Explicación
Sea la efectividad máxima del prefijo de longitud de la unidad. Las transiciones se definen como , donde .
Definimos un arreglo de sumas de prefijos . Entonces podemos expresar como . Ahora evaluamos la primera ecuación con nuestro nuevo valor de :
Sacamos fuera del los términos que no dependen de .
Agrupamos con los términos que dependen solo de .
Para manejar las transiciones de forma eficiente en o , usamos la optimización de envolvente convexa.
Complejidad temporal:
Implementación
#include <bits/stdc++.h>
using namespace std;
// source:
// https://github.com/kth-competitive-programming/kactl/blob/main/content/data-structures/LineContainer.h
// supports insertion of linear functions and querying of MAXIMUM value of x for
// a given x for details on internal implementation, see LineContainer module
// alternatively, learn Li Chao Tree
inline namespace _LineContainer {
bool _Line_Comp_State;
struct Line {
// k is slope, m is intercept, p is intersection point
mutable ll k, m, p;
bool operator<(const Line &o) const { return _Line_Comp_State ? p < o.p : k < o.k; }
};
struct LineContainer : multiset<Line> {
long long div(long long a, long long b) { return a / b - ((a ^ b) < 0 && a % b); }
bool isect(iterator x, iterator y) {
if (y == end()) {
x->p = LLONG_MAX;
return false;
}
if (x->k == y->k) x->p = x->m > y->m ? LLONG_MAX : -LLONG_MAX;
else x->p = div(y->m - x->m, x->k - y->k);
return x->p >= y->p;
}
void add(long long k, long long m) {
auto z = insert({k, m, 0}), y = z++, x = y;
while (isect(y, z)) z = erase(z);
if (x != begin() && isect(--x, y)) isect(x, y = erase(y));
while ((y = x) != begin() && (--x)->p >= y->p) isect(x, erase(y));
}
long long query(long long x) {
assert(!empty());
_Line_Comp_State = 1;
auto l = *lower_bound({0, 0, x});
_Line_Comp_State = 0;
return l.k * x + l.m;
}
};
} // namespace _LineContainer
long long N, A, B, C;
LineContainer lc;
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> N >> A >> B >> C;
long long P = 0, a, dp = 0;
for (int i = 1; i <= N; i++) {
lc.add(-2 * A * P, dp + A * P * P - B * P);
cin >> a;
P += a;
dp = lc.query(P) + A * P * P + B * P + C;
}
cout << dp << '\n';
}