[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;
}
//决策单调性