# 【BZOJ 1911】【APIO 2010】特别行动队

http://www.lydsy.com/JudgeOnline/problem.php?id=1911

$$①f(i)=f(j)+a(sum_i -sum_j)^2 +b(sum_i -sum_j)+c$$

$$②f(i)=f(k)+a(sum_i -sum_k)^2 +b(sum_i -sum_k)+c$$

①和②分别表示从j和k这两个位置的转移过程，且满足$0≤j<k<i$

$$f(k)-f(j)+a(sum_i -sum_k)^2 -a(sum_i -sum_j)^2 +b(sum_i -sum_k) -b(sum_i -sum_j)>0$$

$$f(k)-f(j)+2asum_i(sum_j - sum_k)-a(sum_j^2 - sum_k^2)+b(sum_j -sum_k)>0$$

$$\frac{f(k)-f(j)}{sum_j -sum_k}+2asum_i +b-a(sum_j + sum_k)<0$$

$$2asum_i +b<\frac{[f(k)+asum_k^2]-[f(j)+asum_j^2]}{sum_k -sum_j}$$

$2asum_i +b$是单调递减的，这样就化成了一个斜率优化的式子，对于一个位置$t$，可以把它看成二维平面上坐标为$(sum_t,f(t)+asum_t^2)$的点，用双端队列维护一个这些点的下凸壳进行转移，时间复杂度$O(n)$

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1000003;
typedef long long ll;
int in() {
int k = 0, fh = 1; char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if (c == '-') fh = -1;
for(; c >= '0' && c <= '9'; c = getchar())
k = (k << 3) + (k << 1) + c - '0';
return k * fh;
}

ll f[N], sum[N], key;
int n, a, b, c, q[N];

bool cmp(int x, int y) {
return f[y] + sum[y] * sum[y] * a  - f[x] - sum[x] * sum[x] * a > key * (sum[y] - sum[x]);
}
bool cmpk(int x, int y, int z) {
return (f[z] + sum[z] * sum[z] * a - f[y] - sum[y] * sum[y] * a) * (sum[y] - sum[x])
> (f[y] + sum[y] * sum[y] * a - f[x] - sum[x] * sum[x] * a) * (sum[z] - sum[y]);
}

int main() {
n = in(); a = in(); b = in(); c = in();
sum[0] = 0;
for(int i = 1; i <= n; ++i)
sum[i] = in(), sum[i] += sum[i - 1];

ll qu;
int head = 0, tail = 1, t;
f[0] = 0;
f[1] = sum[1] * sum[1] * a + sum[1] * b + c;
q[0] = 0; q[1] = 1;
for(int i = 2; i <= n; ++i) {
key = sum[i] * a * 2 + b;
t = q[head]; qu = sum[i] - sum[t];
f[i] = f[t] + qu * qu * a + qu * b + c;
while (head < tail && cmpk(q[tail - 1], q[tail], i)) --tail;
q[++tail] = i;
}

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

(￣▽￣")不过最后还是A掉了233

NOI 2017 Bless All
posted @ 2016-07-20 21:48  abclzr  阅读(223)  评论(0编辑  收藏  举报