洛谷 P3628 [APIO2010]特别行动队

题意简述

将n个士兵分为若干组,每组连续,编号为i的士兵战斗力为xi
若i~j士兵为一组,该组初始战斗力为\( s = \sum\limits_{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\n", dp[n]);
}
posted @ 2018-08-13 13:21  xuyixuan  阅读(159)  评论(0编辑  收藏  举报