玩具装箱 BZOJ 1010

玩具装箱

【问题描述】

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。但他希望费用最小.

【输入格式】

第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7

【输出格式】

输出最小费用

【样例输入】

5 4

3

4
2
1
4

【样例输出】

1


题解:

设f[i]为选完前i个最小的费用

那么转移方程:

发现具有决策单调性

那么······

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cstdio>
 6 #include<cmath>
 7 #define big long long
 8 using namespace std;
 9 struct Ti
10 {
11     int x, y, z;
12 }o[1000001];
13 int n, m;
14 big s;
15 big sum[1000001], f[1000001];
16 big sqr(big x)
17 {
18     return x * x;
19 }
20 big Cal(big x, big y)
21 {
22     return f[x] + sqr(sum[y] - sum[x] + y - x - 1 - m);
23 }
24 int Two(int x, int y, int z, int ss)
25 {
26     int l = x, r = y, mi;
27     while(l <= r)
28     {
29         mi = (l + r) >> 1;
30         if(Cal(ss, mi) < Cal(z, mi)) r = mi - 1;
31         else l = mi + 1;
32     }
33     return l;
34 }
35 int main()
36 {
37     scanf("%d%d", &n , &m);
38     for(int i = 1; i <= n; ++i)
39     {
40         scanf("%lld", &s);
41         sum[i] = sum[i - 1] + s;
42     }
43     int t = 1, w = 1, cc;
44     o[1] = (Ti) {0, n, 0};
45     for(int i = 1; i <= n; ++i)
46     {
47         if(i > o[t].y) ++t;
48         f[i] = Cal(o[t].z, i);
49         if(Cal(i, n) < Cal(o[w].z, n))
50         {
51             while(t <= w && Cal(i, o[w].x) < Cal(o[w].z, o[w].x)) --w;
52             if(t <= w)
53             {
54                 cc = Two(o[w].x, o[w].y, o[w].z, i);
55                 o[w].y = cc - 1;
56                 o[++w] = (Ti) {cc, n, i};
57             }
58             else o[++w] = (Ti) {i, n, i};
59         }
60     }
61     printf("%lld", f[n]);
62 }
posted @ 2017-03-02 14:09  草根柴鸡  阅读(202)  评论(0编辑  收藏  举报