标签:
http://www.lydsy.com/JudgeOnline/problem.php?id=1911
夏令营里斜率优化的例题,我调了一晚上,真是弱啊。
先推公式吧($sum_i$表示$x_1 \dots x_i$的和):
$$①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$
然后假设②比①更优,则②的等号右边减去①的等号右边大于0
$$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$$
又因为$sum_j -sum_k < 0$,所以两边同时除以$sum_j -sum_k$:
$$\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)$
夏令营讲题时自己推式子推错了!!!斯巴达!!!!!!!!!好久才发现。式子改正过来后对拍还是错,后来发现改的太急了忘加了两个括号斯巴达!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
为了A掉这道题耗了一晚上,全是脑残和手残造成的,已无力吐槽_(:з」∠)_
#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; while (head < tail && cmp(q[head], q[head + 1])) ++head; 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
标签:
原文地址:http://www.cnblogs.com/abclzr/p/5689837.html