[HNOI2008]玩具装箱toy

 

1010: [HNOI2008]玩具装箱toy

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 3647  Solved: 1242
[Submit][Status][Discuss]

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

HINT

 

Source

 
[Submit][Status][Discuss]

Solution

斜率优化DP。

这一题学到好多, 首先是斜率优化DP, 然后是单调队列维护。 其实这两个知识很早以前我就看过了, 只是一直没有什么时间来学, 今天花了大约2个多小时细细的体会了一下, 豁然开朗的感觉。LOL!!

 

首先:

这道题一开始一定能想到一个O(N^2)的DP方程: 

dp[i] = dp[j] + min(sum[i] - sum[j] + i - j - 1 + L)^2

dp[i] = min(dp[j] + (sum[i] - sum[j] + i - j - 1 + L)^2)

接着化成斜率的形式什么的,可以用笔推导一下, 过程虽然繁琐, 但是很好想的:)

 

再讲讲写率优化吧:

斜率优化,就是把决策的关系写成(Y1-Y2)/(x1-x2)的斜率式,然后用队列维护。

队列中的决策需要保证两个性质 : ① j1<j2<j3<j4....②slope(j1,j2)<slope(j2,j3)<slope(j3,j4)。

 

关于单调队列:

1、对某个阶段i进行决策时候,首先判断用队头决策是否比用队头+1决策优,如果不优,就出队。直到队头决策优。

2、计算阶段i的值。

3、判断 队尾和i的斜率 与 队尾-1和i的斜率 哪个大。如果 队尾-1 大,那就将队尾删除。直到队尾斜率大,然后i入队。

 

Code

View Code
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cstring>
 5 #define maxn 50050
 6 using namespace std;
 7 int d[maxn], head = 1, tail = 1, L, n;
 8 long long dp[maxn], sum[maxn];
 9 
10 bool slope(int i, int j, int k) {
11     return ((dp[i] + sum[i] * sum[i]) - (dp[k] + sum[k] * sum[k])) * (sum[i] - sum[j]) < ((dp[i] + sum[i] * sum[i]) - (dp[j] + sum[j] * sum[j])) * (sum[i] - sum[k]);
12 }
13 
14 long long cal(int i, int j) {
15     return dp[j] + (sum[i] - sum[j] - L) * (sum[i] - sum[j] - L);
16 }
17 
18 void init() {
19     int i, j;
20     scanf("%d%d", &n, &L);
21     L++;
22     for (i = 1; i <= n; i++) {
23         scanf("%d", &j);
24         sum[i] = sum[i - 1] + j + 1;
25     }
26 }
27 
28 void solve() {
29     int i;
30     d[1] = 0;
31     for (i = 1; i <= n; i++) {
32         while (head < tail && cal(i, d[head]) > cal(i, d[head+1])) head++;
33         dp[i] = cal(i, d[head]);
34         while (head < tail && slope(i, d[tail - 1], d[tail])) tail--;
35         d[++tail] = i;
36     }
37     printf("%lld\n", dp[n]);
38 }
39 
40 int main() {
41     init();
42     solve();
43     return 0;
44 }

 

 

posted @ 2013-02-10 20:55  Joker0429  阅读(208)  评论(0编辑  收藏  举报