1. 程式人生 > >APIO 2010 特別行動隊 | 斜率優化DP

APIO 2010 特別行動隊 | 斜率優化DP

dig show read 行動 digi print AR return type

luogu 3628

si表示序列的前綴和
f(i)表示將序列的前i個劃分若幹段的最大價值
f(i)= max{f(j)+a∗(si−sj)2+b∗(si−sj)+c},1≤j<i
= max{−2a*sj*si+f(j)+a*sj*sj−b*sj}+a*si*si+b*si+c,1≤j<i

 1 #include <cstdio>
 2 #include <string>
 3 
 4 typedef long long ll;
 5 
 6 ll a, b, c;
7 8 ll read() { 9 ll x = 0, f = 1; 10 char c = getchar(); 11 while (!isdigit(c)) { 12 if (c == -) f = -1; 13 c = getchar(); 14 } 15 while (isdigit(c)) { 16 x = (x << 3) + (x << 1) + (c ^ 48); 17 c = getchar(); 18 } 19
return x * f; 20 } 21 22 ll s[1000005], f[1000005]; int Q[1000005]; 23 24 ll K(int j) { 25 return -2 * a * s[j]; 26 } 27 28 ll B(int j) { 29 return f[j] + a * s[j] * s[j] - b * s[j]; 30 } 31 32 ll Y(int i, int j) { 33 return K(j) * s[i] + B(j); 34 } 35 36 bool cover(int i, int j, int
k) { 37 ll y1 = (K(i) - K(k)) * (B(j) - B(i)); 38 ll y2 = (K(i) - K(j)) * (B(k) - B(i)); 39 return y1 <= y2; 40 } 41 42 int main() { 43 int n = read(); a = read(), b = read(), c = read(); 44 for (int i = 1; i <= n; ++ i) { 45 ll x = read(); s[i] = s[i - 1] + x; 46 } 47 int l = 0, r = 0; 48 for (int i = 1; i <= n; ++ i) { 49 while (l < r && Y(i, Q[l]) <= Y(i, Q[l + 1])) ++ l; 50 f[i] = Y(i, Q[l]) + a * s[i] * s[i] + b * s[i] + c; 51 while (l < r && cover(i, Q[r], Q[r - 1])) -- r; 52 Q[++r] = i; 53 } 54 printf("%lld\n", f[n]); 55 }

APIO 2010 特別行動隊 | 斜率優化DP