[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;
}
posted @ 2018-12-28 15:44  QvvQ  阅读(142)  评论(0编辑  收藏  举报