题意简述
将n个士兵分为若干组,每组连续,编号为i的士兵战斗力为xi
若i~j士兵为一组,该组初始战斗力为( s = sumlimits_{k = i}^{j}xk ),实际战斗力(a * s^2 + b * s + c)(a,b,c为常数)
求最大实际战斗力
题解思路
( dp[i] = max(dp[j) + a * (s[i] - s[j]) ^ 2 + b * (s[i] - s[j]) + c )
然后斜率优化,单调队列维护
代码
#include <cstdio>
using namespace std;
typedef long long ll;
int n, l, h, t, a, b, c;
int q[1000010];
ll sum[1000010], dp[1000010];
ll sqr(ll x) {return x * x; }
int s1(int x) {return sum[x] * 2 * a; }
int s2(int x) {return sum[x]; }
int s4(int x) {return dp[x] + a * sqr(s2(x)) - b * s2(x); }
double calc(int i, int j) {return (double)(s4(j) - s4(i)) / (s2(j) - s2(i)); }
int main()
{
scanf("%d", &n);
scanf("%d%d%d", &a, &b, &c);
for (register int i = 1; i <= n; ++i)
{
scanf("%d", &sum[i]);
sum[i] += sum[i - 1];
}
h = t = 1;
for (register int i = 1; i <= n; ++i)
{
while (h < t && calc(q[h], q[h + 1]) > s1(i)) ++h;
dp[i] = s4(q[h]) - s1(i) * s2(q[h]) + a * sqr(s2(i)) + b * s2(i) + c;
while (h < t && calc(q[t - 1], q[t]) < calc(q[t], i)) --t;
q[++t] = i;
}
printf("%lld
", dp[n]);
}