# [BZOJ1911][Apio2010]特别行动队

[BZOJ1911][Apio2010]特别行动队

4
-1 10 -20
2 2 3 4

9

DP，令 f(i) 表示前 i 个士兵可以达到的最大修正后的战斗力，则有 f(i) = max{ f(j) + d(j+1 ~ i) | 0 < j < i }，其中d(i ~ j)表示第 i 个士兵到第 j 个士兵组成一队修正之后的战斗力。展开之后得到

f(i) - a·Si2 - b·Si - c = f(j) + a·Sj2 - b·Sj - 2·a·Si · Sj

b = y - k · x，变形得 y = kx + b，斜率k单调递增，我们要求的是b的最大值，所以维护所有(x, y)点构成的上凸壳即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
inline char Getchar() {
int l = fread(buffer, 1, BufferSize, stdin);
tail = (Head = buffer) + l;
}
}
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}

#define maxn 1000010
#define LL long long
int n, a, b, c, S[maxn], q[maxn], l, r;
LL f[maxn];

double slop(int i, int j) {
double yi = i ? f[i] + (double)a * S[i] * S[i] - (double)b * S[i] : 0.0, yj = f[j] + (double)a * S[j] * S[j] - (double)b * S[j];
double xi = i ? S[i] : 0, xj = S[j];
return (yi - yj) / (xi - xj);
}

int main() {
for(int i = 1; i <= n; i++) S[i] = S[i-1] + read();

f[0] = 0;
l = r = 1; q[1] = 0;
for(int i = 1; i <= n; i++) {
while(l < r && slop(q[l], q[l+1]) > 2.0 * a * S[i]) l++;
int j = q[l];
f[i] = f[j] + (LL)a * S[j] * S[j] - (LL)b * S[j] - 2ll * a * S[i] * S[j] + (LL)a * S[i] * S[i] + (LL)b * S[i] + c;
while(l < r && slop(q[r], i) >= slop(q[r-1], q[r])) r--;
q[++r] = i;
}

printf("%lld\n", f[n]);

return 0;
}


posted @ 2016-04-20 21:18  xjr01  阅读(233)  评论(0编辑  收藏  举报