BZOJ1010【HNOI2008】玩具装箱toy <斜率优化>

Problem

【HNOI2008】玩具装箱toy

Time  Limit:  10  Sec\mathrm{Time\;Limit:\;10\;Sec}
Memory  Limit:  162  MB\mathrm{Memory\;Limit:\;162\;MB}

Description

PP教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。PP教授有编号为1N1\sim NNN件玩具,第ii件玩具经过压缩后变成一维长度为CiC_i.为了方便整理,PP教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第ii件玩具到第jj个玩具放到一个容器中,那么容器的长度将为 x=ji+k=ijCkx=j-i+\sum_{k=i}^{j}C_k制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为XX,其制作费用为(XL)2(X-L)^2.其中LL是一个常量。PP教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过LL。但他希望费用最小.

Input

第一行输入两个整数N,LN,L.接下来NN行输入CiC_i.
1N50000,1L,Ci1071\le N\le50000,1\le L,C_i\le10^7

Output

输出最小费用.

Sample Input

1
2
3
4
5
6
5 4
3
4
2
1
4

Sample Output

1
1

标签:斜率优化DP

Solution

L=L+1L=L+1,有如下DPDP方程:f[i]=minj=0i1{f[j]+[(ij+k=jiCk)L]2}f[i]=\min_{j=0}^{i-1}\{f[j]+[(i-j+\sum_{k=j}^{i}C_k)-L]^2\}

预处理s[i]=j=1iCj,  w[i]=s[i]+is[i]=\sum_{j=1}^{i}C_j,\;w[i]=s[i]+i。对于当前DPDP到的位置ii,必然存在p,q[0,i)p,q\in[0,i),使得

f[p]+[(ip+k=piCk)L]2f[q]+[(iq+k=qiCk)L]2f[p]+(w[i]w[p]L)2f[q]+(w[i]w[q]L)2f[p]+w[i]2+w[p]2+L22×w[i]×w[p]2×w[i]×L+2×w[p]×Lf[q]+w[i]2+w[q]2+L22×w[i]×w[q]2×w[i]×L+2×w[q]×Lf[p]+(w[p]+L)22×w[i]×w[p]f[q]+(w[q]+L)22×w[i]×w[q](f[p]f[q])+((w[p]+L)2(w[q]+L)2)2×(w[p]w[q])w[i]\begin{aligned} f[p]+[(i-p+\sum_{k=p}^{i}C_k)-L]^2&\le f[q]+[(i-q+\sum_{k=q}^{i}C_k)-L]^2\\ &\Updownarrow\\ f[p]+(w[i]-w[p]-L)^2&\le f[q]+(w[i]-w[q]-L)^2\\ &\Updownarrow\\ f[p]+w[i]^2+w[p]^2+L^2-2\times w[i]&\times w[p]-2\times w[i]\times L+2\times w[p]\times L\\ &\le\\ f[q]+w[i]^2+w[q]^2+L^2-2\times w[i]&\times w[q]-2\times w[i]\times L+2\times w[q]\times L\\ &\Updownarrow\\ f[p]+(w[p]+L)^2-2\times w[i]\times w[p]&\le f[q]+(w[q]+L)^2-2\times w[i]\times w[q]\\ &\Updownarrow\\ \frac{(f[p]-f[q])+((w[p]+L)^2-(w[q]+L)^2)}{2\times(w[p]-w[q])}&\le w[i]\\ \end{aligned}

k(p,q)=(f[p]f[q])+((w[p]+L)2(w[q]+L)2)2×(w[p]w[q])w[i]    p  is  better  than  q\therefore k(p,q)=\frac{(f[p]-f[q])+((w[p]+L)^2-(w[q]+L)^2)}{2\times(w[p]-w[q])}\le w[i]\iff p\;is\;better\;than\;q

按照此斜率维护单调栈即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <bits/stdc++.h>
#define MAX_N 50000
using namespace std;
typedef double dnt;
typedef long long lnt;
template <class T>
inline void read(T &x) {
x = 0; int c = getchar(), f = 1;
for (; !isdigit(c); c = getchar()) if (c == 45) f = -1;
for (; isdigit(c); c = getchar()) (x *= 10) += f*(c-'0');
}
int n, l, sta[MAX_N+5], s, t; lnt f[MAX_N+5], w[MAX_N+5];
dnt calc(int p, int q) {return (f[p]-f[q]+(w[p]+l)*(w[p]+l)-(w[q]+l)*(w[q]+l))/(2.0*(w[p]-w[q]));}
int main() {
read(n), read(l), l++;
for (int i = 1; i <= n; i++) read(w[i]), w[i] += w[i-1];
for (int i = 1; i <= n; i++) w[i] += i;
for (int i = 1; i <= n; i++) {
while (s < t && calc(sta[s+1], sta[s]) <= w[i]) s++;
f[i] = f[sta[s]]+(w[i]-w[sta[s]]-l)*(w[i]-w[sta[s]]-l);
while (s < t && calc(sta[t], sta[t-1]) > calc(i, sta[t])) t--;
sta[++t] = i;
}
return printf("%lld", f[n]), 0;
}