把长度为 n 的序列 x 划成一段段, 设某段元素之和为 x, 则该段战斗力为 ax^2 + bx + c. 求每段战斗力之和的最大值. (1 ≤ n ≤ 10^6, -5 ≤ a ≤ -1, |b|,|c| ≤ 10^7, 1 ≤ x[i] ≤ 100) 战斗力是关于
设
令
由于要最大化
大于二次就不能斜率优化了, 因为包含
const int N = 1e6 + 1;
typedef long long ll;
int a, b, c, s[N], Q[N], * p = Q, * q = Q-1;
ll f[N];
inline ll cross(ll x1, ll y1, ll x2, ll y2)
{
return x1*y2 - x2*y1;
}
inline ll x(int i)
{
return s[i];
}
inline ll y(int i)
{
return f[i] + 1LL*a*s[i]*s[i];
}
int main()
{
int n;
scanf("%d%d%d%d", &n, &a, &b, &c);
rep (i, 1, n+1) scanf("%d", s+i), s[i] += s[i-1];
*++q = 0;
rep (i, 1, n+1)
{
ll k = 2LL*a*s[i] + b;
while (q-p > 0 && cross(x(*(p+1))-x(*p), y(*(p+1))-y(*p), 1, k) <= 0) ++p;
f[i] = y(*p) - k*x(*p) + 1LL*a*s[i]*s[i] + 1LL*b*s[i] + c;
ll x0 = x(i), y0 = y(i);
while (q-p > 0 && cross(x(*q)-x0, y(*q)-y0, x(*(q-1))-x0, y(*(q-1))-y0) <= 0) --q;
*++q = i;
}
printf("%lld\n", f[n]);
return 0;
}