BZOJ 1010 玩具装箱 斜率优化DP

详情见 http://www.cnblogs.com/proverbs/archive/2013/02/01/2713109.html(我觉得这里面讲得已经够详细了,我就不赘述了)

还是来回忆一下做这道题的历程吧!一开始的确有点想错了,但马上又反应过来,清楚了题意。写了个 n^2 的算法。很明显,对于n <=  50000 的数据,肯定是要TLE的。(援引我看博客过程中看到的一句话来形容就是“省选题的数据就是硬”。)没办法,只能上网找百度(太弱了)。一开始的确有点茫然,但马上就决定要自己推导一下,马上思路就清晰了。但对于该算法的正确性还有所怀疑,所以一个下午都在思考(上课都是恍恍惚惚的)。后来大致明白了。

一开始有疑惑的地方有,为什么可以直接在队首维护后的队列中取出首位呢? 原因在于 设 i  < j 如果一开始 j 比 i 更优那么 i 会被踢出队列。那为什么不可以设 i < j < k 中 j 虽然比 i 差 但 k 比 i 更优呢! 原因在于如果 i < j < k 三者这样的位置关系,我们是会在队尾维护的过程中把这种情况去掉。 所以可以直接在队首维护后的队列中取出首位。

斜率优化其实就是把每个状态看上直角坐标系上离散的点抽象出x,y 表示斜率 (y2 - y1) / (x2 - x1) 于一个关系状态i个函数的关系,然后维护点见斜率的上凸性或者下凸性。具体的情况要看于i有关的函数的单调性。

说一些注意事项:

注意斜率尽量中乘法,不要中实数(的确,误差影响很大),如有必要全用long long,以免溢出。注意 x2 - x1可能小于0不等式的负号要改变;

这道题一开始用 int , WA了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #define rep(i,j,k) for(int i = j; i <= k; i++)
 4 #define down(i,j,k) for(int i = j; i >= k; i--)
 5 #define sqr(i) (i)*(i)
 6 #define maxn 50010
 7 #define LL long long
 8 using namespace std;
 9
10 LL sum[maxn], c[maxn], dep[maxn], dp[maxn];
11 double slope(int i, int j){
12     return  1.0*(dp[i]+sqr(sum[i])-dp[j]-sqr(sum[j]))/(sum[i]-sum[j]);
13 }
14
15 int main()
16 {
17     LL n, l, x;
18     scanf("%lld%lld", &n,&l);
19     c[0] = 0;
20     rep(i,1,n){
21         scanf("%lld",&x);
22         c[i] = c[i-1] + x;
23         sum[i] = c[i] + i;
24     }
25     LL s = 0, t = 0;
26     dp[0] = 0, dep[0] = 0;
27     rep(i,1,n){
28         LL m = sum[i] - l - 1;
29         while( s < t && slope(dep[s+1],dep[s]) <= 2 * m ) s++;
30         LL j = dep[s];
31         dp[i] = dp[j] + sqr(m-sum[j]);
32         while( s < t && slope(dep[t],dep[t-1]) >= slope(i,dep[t]) ) t--;
33         dep[++t] = i;
34     }
35     cout<<dp[n]<<endl;
36     return 0;
37 }

1010: [HNOI2008]玩具装箱toy

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 7823  Solved: 3015
[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

附POJ 3709

这道题与上面的差不多,这是多了一个每组应至少有k个数的限制。对此援引从博客上看到的

“好,以下考虑每组不少于K个元素这个限制。

要解决这个限制,只需延迟加入的时机即可。

若延迟K-1个回合加入,有可能使前一组的个数少于K个。

若延迟2*k-1个回合加入,则不会出现这情况。但此时加入的数应是i-k+1(假设是第I回合)” // 重点

以及延迟加入时机后,队尾维护的代码也要修改(查错查了半天)。

详情见 http://blog.sina.com.cn/s/blog_5f5353cc0100jxxo.html

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #define rep(i,j,k) for(int i = j; i <= k; i++)
 5 #define maxn 500010
 6 #define LL long long
 7 using namespace std;
 8
 9 LL num[maxn], sum[maxn], f[maxn], q[maxn];
10 int head, tail;
11
12 LL G(int k,int j) {
13        return f[j]-f[k]-sum[j]+sum[k]+j*num[j+1]-k*num[k+1];
14 }
15
16 LL S(int k,int j) {
17        return num[j+1]-num[k+1];
18 }
19
20 int read()
21 {
22     int s = 0, t = 1; char c = getchar();
23     while( !isdigit(c) ){
24         if( c == ‘-‘ ) t = -1; c = getchar();
25     }
26     while( isdigit(c) ){
27         s = s * 10 + c - ‘0‘; c = getchar();
28     }
29     return s * t;
30 }
31
32 int main()
33 {
34     int t = read();
35     while( t-- ){
36         int n = read(), k = read();
37         sum[0] = f[0] = q[0] = head = tail = 0;
38         rep(i,1,n){
39             num[i] = read();
40             sum[i] = sum[i-1] + num[i];
41         }
42         rep(i,1,n){
43             while( head < tail && G(q[head+1],q[head])>=i*S(q[head+1],q[head]) ) head++;
44             int j = q[head];
45             f[i] = f[j] + sum[i] - sum[j] - num[j+1] * (i-j);
46             if( i>=2*k-1 ) {
47                 q[++tail]=i-k+1;
48             }
49             while( head < tail && G(q[tail-1],q[tail-2]) * S(q[tail],q[tail-1])  >= G(q[tail],q[tail-1]) * S(q[tail-1],q[tail-2] ) ) {
50                 q[tail-1] = q[tail];
51                 tail--;
52             }
53         }
54         cout<<f[n]<<endl;
55     }
56     return 0;
57 }

将题目转化下:将一个升序的,有N个元素的序列,分组。要求每组的元素不少于K个,计算出组内各元素与最小元素的之差的和,将每组的这个值加起来,其和要最小。

很容易可以得出一个结论:连续取比离散取得到的结果要好(很容易证,所以不证)。

时间: 2024-09-30 15:37:39

BZOJ 1010 玩具装箱 斜率优化DP的相关文章

BZOJ 1010 玩具装箱toy(四边形不等式优化DP)(HNOI 2008)

Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<

【斜率DP】BZOJ 1010:玩具装箱

1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7537  Solved: 2888[Submit][Status][Discuss] Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P

bzoj 1010 玩具装箱toy -斜率优化

P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的

bzoj 1010 玩具装箱toy

摘自YYF的blog,斜率优化,敬一个! P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sig

BZOJ 1010 玩具装箱

斜率优化. 事实上是选一个大于某个数的最小斜率.维护下凸壳. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 50050 using namespace std; long long n,c,s[maxn],dp[maxn],q[maxn],l=1,r=0; double slop(long long j,long long k) {

BZOJ 1010 HNOI2008 玩具装箱 斜率优化

题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1010 Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度

bzoj 4518 [Sdoi2016]征途 (斜率优化DP)

我犯了sb错误然后调了1个小时......队列写错了 斜率k递增,b取最小值,队列维护凸包即可 f[0]的预处理好像有些奇怪???我把inf调大就过了??? 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #define il inline 5 #define ll long long 6 #define N 3010 7 #define inf 66666666 8 using nam

bzoj 1010 [HNOI2008]玩具装箱toy(DP的斜率优化)

1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7874  Solved: 3047[Submit][Status][Discuss] Description P 教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维 容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理

BZOJ 1010: [HNOI2008]玩具装箱toy 斜率优化DP

1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的.同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器