cychester

BZOJ 1911 [APIO2010] 特别行动队 - 斜率优化dp

题解

非常显然的$O(n^2)$ 的dp转移方程 :

$ F_i  = \max( F_j +  a \times (S_i - S_j) ^2 + b \times (S_i - S_j ) + c) $ 数组S为前缀和

进行一波分离后变成了 $ F_j + a \times (S_j)^2 - b \times S_j = 2a \times S_i \times S_j - b \times S_i - c + F_i$。

左边的一串式子为纵坐标, $S_j$ 为横坐标, $2a \times  S_i  $当做斜率, 套上斜率优化板子就可以了

注意维护的是上凸壳

 

代码

 1 #include<cstring>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #define rd read()
 5 #define rep(i,a,b) for(int i = (a); i <= (b); ++i)
 6 #define per(i,a,b) for(int i = (a); i >= (b); --i)
 7 #define ll long long
 8 using namespace std;
 9  
10 const int N = 1e6 + 1e5;
11  
12 ll f[N], a, b, c, s[N], q[N], sum[N], n;
13  
14 int read() {
15     int X = 0, p = 1; char c = getchar();
16     for(; c > '9' || c < '0'; c = getchar()) if( c == '-') p = -1;
17     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 + c - '0';
18     return X * p;
19 }
20  
21 double caly(int A) {
22     return f[A] + a * sum[A] * sum[A] - b * sum[A];
23 }
24  
25 double calk(int A, int B) {
26     double ax = sum[A], bx = sum[B], ay = caly(A), by = caly(B);
27     return (by - ay) / (bx - ax);
28 }
29  
30  
31 int main()
32 {
33     n = rd;
34     a = rd; b = rd; c = rd;
35     rep(i, 1, n) s[i] = rd, sum[i] = sum[i - 1] + s[i];
36     int l = 1, r = 1;
37     rep(i, 1, n) {
38         while(l < r && calk(q[l], q[l + 1]) >= 2 * a * sum[i]) l++;
39         ll x = sum[i] - sum[q[l]];
40         f[i] = f[q[l]] + a * x * x + b * x + c;
41         while(l < r && calk(q[r - 1], q[r]) <= calk(q[r], i)) r--;
42         q[++r] = i;
43     }
44     printf("%lld\n", f[n]);
45 }
46 
View Code

 

posted on 2018-08-19 19:30  cychester  阅读(133)  评论(0编辑  收藏  举报

导航