[BZOJ4518][SDOI2016]征途[斜率优化]
王道征途
\[\text{题目要求的东西可以化成}m\times \sum_{i=1}^m{d\left[ i \right] ^2-pre\left[ n \right] ^2}
\\
\text{对于}\sum_{i=1}^m{d\left[ i \right] ^2\text{做DP}}
\\
f\left[ i \right] \left[ j \right] \text{表示前}j\text{个分成}i\text{段的最小代价}
\\
f\left[ i \right] \left[ j \right] =\min_{k\in \text{[1,}i\text{)}} \left\{ f\left[ i-1 \right] \left[ k \right] +\left( pre\left[ i \right] -pre\left[ k \right] \right) ^2 \right\}
\\
\text{设}j\text{优于}k
\\
\text{则}f\left[ i-1 \right] \left[ j \right] +\left( pre\left[ i \right] -pre\left[ j \right] \right) ^2<f\left[ i-1 \right] \left[ k \right] +\left( pre\left[ i \right] -pre\left[ k \right] \right) ^2
\\
\text{整理得}
\\
\frac{f\left[ i-1 \right] \left[ j \right] -f\left[ i-1 \right] \left[ k \right] +pre\left[ j \right] -pre\left[ k \right]}{pre\left[ j \right] -pre\left[ k \right]}<2\times pre\left[ i \right]
\]
int a[3005], n, m, pre[3005], q[3005], p;
ll f[2][3005];
inline lf slope(int x, int y) {
return (f[!p][x] - f[!p][y] + sqr(pre[x]) - sqr(pre[y])) / (1.0 * pre[x] - pre[y]);
}
int main() {
#ifdef LOCAL_DEBUG
Debug = 1; double tim1 = clock();
// freopen("data.in", "r", stdin) && freopen("data.out", "w", stdout);
#endif
in, n, m;
lop(i,1,n) {in, a[i]; pre[i] = pre[i-1] + a[i];}
lop(i,1,n) f[0][i] = infl;
lop(i,1,m) {
p = i & 1;
int h = 0, t = 0;
lop(j,1,n) {
while(h < t && slope(q[h+1], q[h]) < 2 * pre[j]) ++h;
f[p][j] = f[!p][q[h]] + sqr(pre[j] - pre[q[h]]);
// cout << p << ' ' << j << ' ' << f[p][j] << endl;
while(h < t && slope(q[t], q[t-1]) > slope(q[t], j)) --t;
q[++t] = j;
}
}
out, f[p][n] * m - sqr(pre[n]);
#ifdef LOCAL_DEBUG
fprintf(stderr, "\ntime:%.5lfms", (clock() - tim1) / CLOCKS_PER_SEC * 1000);
#endif
return 0;
}