[BZOJ1010][HNOI2008]玩具装箱toy[斜率优化+决策单调性 三种写法]

\[f\left[ i \right] =\min \left\{ f\left[ j \right] +\left( i-j-1+pre\left[ i \right] -pre\left[ j \right] -l \right) ^2 \right\} \\ \text{令}g\left( i \right) =pre\left[ i \right] +i,c=1+l \\ f\left[ i \right] =\min \left\{ f\left[ j \right] +\left( g\left( i \right) -c-g\left( j \right) \right) ^2 \right\} \\ =\left( g\left( i \right) -c \right) ^2+\min \left\{ f\left[ j \right] -2\times \left( g\left( i \right) -c \right) \times g\left( j \right) +g\left( j \right) ^2 \right\} \\ \text{设}j\text{优于}k \\ f\left[ j \right] -2\times \left( g\left( i \right) -c \right) \times g\left( j \right) +g\left( j \right) ^2<f\left[ k \right] -2\times \left( g\left( i \right) -c \right) \times g\left( k \right) +g\left( k \right) ^2 \\ f\left[ j \right] -f\left[ k \right] +g\left( j \right) ^2-g\left( k \right) ^2<2\times \left( g\left( i \right) -c \right) \left( g\left( j \right) -g\left( k \right) \right) \\ \frac{f\left[ i \right] -f\left[ k \right] +g\left( j \right) ^2-g\left( k \right) ^2}{g\left( j \right) -g\left( k \right)}<2\times \left( g\left( i \right) -c \right) \\ \]

这题满足决策单调性

同时如果将dp柿子写成 \(y=kx+b\) 的话,k和x都单调

//凸壳上二分
ll f[MAXN>>1], pre[MAXN>>1];
int n, a[MAXN>>1], l, c, q[MAXN>>1], h, t;
    
//设 x < y 且 slope(x, y) < 2 * (pre[i] - c) 则从y转移更优
 
inline lf slope(int x, int y) {
  return 1.0 * (f[x] - f[y] + sqr(pre[x]) - sqr(pre[y])) / (pre[x] - pre[y]);
}
    
inline ll DP(int i, int x) {
  return f[x] + sqr(pre[i] - c - pre[x]);
}
 
inline int Get(int i, int r) {
  int ret = 0, l = 0; --r;//开始是0
  while (l <= r) {
    int mid = l + r >> 1;
    if (slope(q[mid+1], q[mid]) < 2 * (pre[i] - c)) //从q[mid+1]转移更优
      l = mid + 1, ret = mid + 1;
    else r = mid - 1;
  }
  return q[ret];
}
// 5 4
// 3 4 2 1 4
int main() {
  in, n, l;
  c = l + 1;
  lop(i,1,n) in, a[i];
  lop(i,1,n) pre[i] = pre[i-1] + a[i];
  lop(i,1,n) pre[i] += i;
  fill(f+1, f+1+n, infl);
  lop(i,1,n) {
//维护凸壳,在凸壳上二分
    int P = Get(i, t);
    f[i] = DP(i, P);
    while(t && slope(q[t], q[t-1]) >= slope(q[t], i)) --t;
    q[++t] = i;
  }
  cout << f[n];
  return 0;
}



ll f[MAXN], pre[MAXN];
int n, a[MAXN], l, c, q[MAXN], h, t;
    
inline llf slope(int x, int y) {
  return 1.0L * (f[x] - f[y] + sqr(pre[x]) - sqr(pre[y])) / (pre[x] - pre[y]);
}
    
int main() {
  in, n, l;
  c = l + 1;
  lop(i,1,n) in, a[i];
  lop(i,1,n) pre[i] = pre[i-1] + a[i];
  lop(i,1,n) pre[i] += i;
  fill(f+1, f+1+n, infl);
  lop(i,1,n) {
    while(h < t && slope(q[h], q[h+1]) < 2 * (pre[i] - c)) ++h;
    f[i] = f[q[h]] + sqr(pre[i] - c - pre[q[h]]);
    while(h < t && slope(q[t], q[t-1]) > slope(q[t], i)) --t;
    q[++t] = i;
  }
  cout << f[n];
  return 0;
}
//斜率优化



ll f[MAXN>>1], pre[MAXN>>1];
int n, a[MAXN>>1], c, q[MAXN>>1], h, t, L[MAXN>>1], R[MAXN>>1], l;
     
inline ll DP(int i, int x) {
  return f[x] + sqr(pre[i] - c - pre[x]);
}
 
inline int Get_pos(int x, int y) {//找到x比y优的第一个位置
  int l = max(x, y), r = n, ans = 1e9;
  while (l <= r) {
    int mid = l + r >> 1;
    if (DP(mid, x) >= DP(mid, y)) ans = mid, l = mid + 1;
    else r = mid - 1;
  }
  return ans + (DP(ans, x) > DP(ans, y));//某个位置 以后 x比y优,所以看看是不是以后
}
 
int main() {
  in, n, l;
  c = l + 1;
  lop(i,1,n) in, a[i];
  lop(i,1,n) pre[i] = pre[i-1] + a[i];
  lop(i,1,n) pre[i] += i;
  fill(f+1, f+1+n, infl);
  L[0] = 1, R[0] = n;
  lop(i,1,n) {  
    while (h < t && R[q[h]] < i) ++h;
    f[i] = DP(i, q[h]);
    while (h < t && Get_pos(i, q[t]) < Get_pos(q[t], q[t-1])) --t;
    int u = Get_pos(i, q[t]);
    R[q[t]] = u - 1, q[++t] = i, L[i] = u, R[i] = n;
  }
  cout << f[n];
  return 0;
}
//决策单调性
posted @ 2018-12-28 15:41  QvvQ  阅读(197)  评论(1编辑  收藏  举报