[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

5 4
3
4
2
1
4

Sample Output

1

分析

     这已经是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)$。

 

 1 /**************************************************************
 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 }
单调队列dp

 

posted @ 2015-03-26 12:11  Asm.Definer  阅读(202)  评论(0编辑  收藏  举报