[bzoj1010](HNOI2008)玩具装箱toy(动态规划+斜率优化+单调队列)
Description
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有 的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具 经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加 入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作 出任意长度的容器,甚至超过L。但他希望费用最小.
Input
第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7
Output
输出最小费用
Sample Input
3
4
2
1
4
Sample Output
分析
这已经是HNOI2008第三道dp了吧……
首先我们还是要写出转移方程:$$f(i) = \min_{0 \leq j < i} \{ f(j) + (S(i) - S(j) - L - 1)^2 \} $$
其中$S(i) = \sum\limits_{j =1}^i (C(j) + 1).$
然后把方程转化一下:$$f(i) = (S(i) - L - 1)^2 + \\ \min_{0 \leq j<i} \{-2(S(i)-L-1)S(j) + f(j) + S(j)^2 \}$$
就可以设$2(S(i)-L-1)$为斜率,$S(j)和 f(j) + S(j)^2$分别为横纵坐标建立凸包进行斜率优化,复杂度$O(NlogN)$.
最后可以发现每次对凸包进行二分查找时的斜率$2(S(i)-L-1)$是随i单调递增的……于是我们可以用单调队列优化到$O(n)$。
2 Problem: 1010
3 User: AsmDef
4 Language: C++
5 Result: Accepted
6 Time:76 ms
7 Memory:2176 kb
8 ****************************************************************/
9
10 #include <cctype>
11 #include <cstdio>
12 using namespace std;
13 template<typename T>inline void getd(T &x){
14 char c = getchar(); bool minus = 0;
15 while(!isdigit(c) && c != '-')c = getchar();
16 if(c == '-')minus = 1, c = getchar();
17 x = c - '0';
18 while(isdigit(c = getchar()))x = x * 10 + c - '0';
19 if(minus)x = -x;
20 }
21 /*========================================================*/
22 typedef long long LL;
23 const int maxn = 50003;
24 int N, L, V[maxn], it1 = 0, it2 = 1;
25 LL S, X[maxn], Y[maxn], f[maxn];
26 #define cmp(x, y, j, k)\
27 (y<=Y[j])?1:((k<0)?0:((x-X[j])*(Y[j]-Y[k]) >= (X[j]-X[k])*(y-Y[j])))
28
29 inline void insert(LL x, LL y){
30 if(it2 <= it1+1){
31 X[it2] = x, Y[it2] = y;
32 ++it2;
33 return;
34 }
35 while(it2 > it1 && cmp(x, y, it2-1, it2-2))--it2;
36 X[it2] = x, Y[it2] = y;
37 ++it2;
38 }
39 inline void dp(){
40 int i;
41 LL k, t, b1, b2, y;
42 for(i = 1;i <= N;++i){
43 S += V[i];
44 t = S - L - 1, k = - t << 1;
45 b2 = k * X[it1] + Y[it1];
46 if(it2 - it1 <= 1){
47 f[i] = t * t + b2;
48 y = f[i] + S * S;
49 insert(S, y);
50 continue;
51 }
52 while(it1 + 1 < it2){
53 b1 = b2, b2 = k * X[it1+1] + Y[it1+1];
54 if(b1 >= b2)++it1;
55 else break;
56 }
57 f[i] = t * t + k * X[it1] + Y[it1];
58 y = f[i] + S * S;
59 insert(S, y);
60 }
61 printf("%lld\n", f[N]);
62 }
63 int main(){
64 #if defined DEBUG
65 freopen("test", "r", stdin);
66 #else
67 //freopen("bzoj_1010.in", "r", stdin);
68 //freopen("bzoj_1010.out", "w", stdout);
69 #endif
70 int i, C;
71 getd(N), getd(L);
72 for(i = 1;i <= N;++i)
73 getd(C), V[i] = C + 1;
74 dp();
75 return 0;
76 }