题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1010

思路


斜率优化DP

我们知道,有些DP方程可以转化成DP[i]=f[j]+x[i]的形式,其中f[j]中保存了只与j相关的量。这样的DP方程我们可以用单调队列进行优化,从而使得O(n^2)的复杂度降到O(n)。

可是并不是所有的方程都可以转化成上面的形式,比如dp[i]=dp[j]+(x[i]-x[j])*(x[i]-x[j])。如果把右边的乘法化开的话,会得到x[i]*x[j]的项。这就没办法使得f[j]里只存在于j相关的量了。于是上面的单调队列优化方法就不好使了,所以我们需要一种新的优化方法,叫做斜率优化。

拿本题来说,我们设dp[i]表示装到第i个玩具的时候最少的花费,sum[i]表示前i个玩具的长度和。于是方程就是:

dp[i]  = min{ dp[j] + [i+sum[i]-(j+1+sum[j])-L]2 };

题目的N<=50000,二维铁定超时了。我们就来看看斜率优化如何做到从O(n^2)复杂度降到O(n)。

分析:

我们假设k<j<i。如果在j的时候决策要比在k的时候决策好,那么也是就是dp[j] + [i+sum[i]-(j+1+sum[j])-L]< dp[k] + [i+sum[i]-(j+1+sum[k])-L]2。(因为是最小花费,所以优就是小于)

两边移项一下得到:[dp[j]+(j+1+sum[j])^2-(dp[k]+(k+1+sum[k])^2)]/(2*( (j+1+sum[j])-(k+1+sum[k]) )) < (i + sum[i]-L)。我们把dp[j]-num[j]^2看做是yj,把2*num[j]看成是xj。

那么不就是(yj-yk)/(xj-xk) < A[i]么?   左边是不是斜率的表示?

那么(yj-yk)/(xj-xk) < A[i]说明了什么呢?  我们前面是假设j的决策比k的决策要好才得到这个表示的,那么g[j,k]=(yj-yk)/(xj-xk) < A[i]代表这j的决策比k的决策要更优

斜率优化在于:①设k<j<i,如果g[i,j] < g[j,k],那么j点便永远不可能成为最优解,可以直接将它踢出我们的最优解集。‘

为什么呢?我们假设g[i,j] < A[i],那么就是说i点要比j点优,排除j点。如果g[i,j] >= A[i],那么j点此时是比i点要更优,但是同时g[j,k]>g[i,j]>A[i]。这说明还有k点会比j点更优,同样排除j点。排除多余的点,这便是一种优化!

由于我们排除了g[i,j] < g[j,k]的情况,所以整个有效点集呈现一种下凸性质,即k j的斜率要小于j i的斜率。这样,从左到右的斜率之间就是单调递增的了,所以我们就可以对g维护一个单调队列。

同时,函数A[i]也要具有单调递增的特性,所以第二个优化就在于:②如果单调队列的头两个点为i, j,斜率g[j, i] < A[i],则说明j优于i,并且由于A单调递增,所以g[j,i]恒小于A[],所以可以直接把i排除掉。

于是对于这类题斜率优化做法可以总结如下:

1,用一个单调队列来维护解集。

2,假设队列中从头到尾已经有元素a b c。那么当d要入队的时候,我们维护队列的下凸性质,即如果g[d,c]<g[c language=",b"][/c],那么就将c点删除。直到找到g[d,x]>=g[x,y]为止,并将d点加入在该位置中。

3,求解时候,从队头开始,如果已有元素a b c,当i点要求解时,如果g[b,a]<A[i],那么说明b点比a点更优,a点可以排除,于是a出队。最后dp[i]=getDp(q[head])。


代码

[cpp]
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i, begin, end) for (int i = begin; i <= end; i ++)
using namespace std;

long long dp[50005], sum[50005];
vector <int> Q;
int n, L;
inline long long getDP(int i, int j){
return dp[j] + (i+sum[i]-(j+1+sum[j])-L) * (i+sum[i]-(j+1+sum[j])-L);
}
inline double getUP(int j, int k){
return (double)dp[j] + (double)(j+1+sum[j]) * (double)(j+1+sum[j]) - ((double)dp[k] + (double)(k+1+sum[k]) * (double)(k+1+sum[k]));
}
inline double getDOWN(int j, int k){
return 2.0 * ((j+1+sum[j]) - (k+1+sum[k]));
}
inline double getRIGHT(int i){
return (double)(sum[i] + i - L);
}
inline double slope(int j, int k){
return getUP(j, k) / getDOWN(j, k);
}
int main(){
scanf("%d %d", &n, &L);
sum[0] = 0, dp[0] = 0;
for (int i = 1; i <= n; i ++){
scanf("%lld", &sum[i]);
sum[i] += sum[i-1];
}
Q.clear();
Q.push_back(0);
for (int i = 1; i <= n; i ++){
while((int)Q.size() > 1 && slope(Q[1], Q[0]) <= getRIGHT(i))
Q.erase(Q.begin());
int tmp = Q[0];
dp[i] = getDP(i, Q[0]);
while( (int)Q.size() > 1 && slope(Q[(int)Q.size()-1], Q[(int)Q.size()-2]) >= slope(i, Q[(int)Q.size()-1]) )
Q.pop_back();
Q.push_back(i);
}
printf("%lld\n", dp[n]);
return 0;
}
[/cpp]

BZOJ 1010 [HNOI2008]玩具装箱 (斜率优化DP)的更多相关文章

  1. BZOJ 1010 HNOI2008 玩具装箱 斜率优化

    题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1010 Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的 ...

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

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7874  Solved: 3047[Submit][St ...

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

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 9812  Solved: 3978[Submit][St ...

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

    1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再 ...

  5. Bzoj 1010: [HNOI2008]玩具装箱toy(斜率优化)

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MB Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定 ...

  6. BZOJ 1010 [HNOI2008]玩具装箱toy

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7184  Solved: 2724[Submit][St ...

  7. BZOJ 1010: [HNOI2008]玩具装箱toy(斜率优化dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1010 题意: 思路: 容易得到朴素的递归方程:$dp(i)=min(dp(i),dp(k)+(i-k ...

  8. BZOJ 1010 [HNOI2008]玩具装箱toy:斜率优化dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1010 题意: 有n条线段,长度分别为C[i]. 你需要将所有的线段分成若干组,每组中线段的 ...

  9. BZOJ.1010.[HNOI2008]玩具装箱toy(DP 斜率优化/单调队列 决策单调性)

    题目链接 斜率优化 不说了 网上很多 这的比较详细->Click Here or Here //1700kb 60ms #include<cstdio> #include<cc ...

随机推荐

  1. IOS自动化定位方式

    原文地址http://blog.csdn.net/wuyepiaoxue789/article/details/77885136 元素属性的介绍 type:元素类型,与className作用一致,如: ...

  2. php.ini优化,,,php-fpm

    无论是apache还是nginx,php.ini都是合适的.而php-fpm.conf适合nginx+fcgi的配置. 1)打开PHP的安全模式 PHP的安全模式是个非常重要的PHP内嵌的安全机制,能 ...

  3. flask内置session原理

    内置session原理 请求到来 当请求进来之后,先执行Flask对象的 __call__ 方法 def wsgi_app(self, environ, start_response): # 获取请求 ...

  4. C语言基础温故

    一.C语言中数组动态增长有哪些方法? 1.在原数组单元后面是没法再扩长的,因为后面的单元没法保证一定有.所以,数组原址动态增长肯定是不行的: 2.要么定义长一点的数组,要么自已把N个数组用链表串起来, ...

  5. C++中去掉string字符串中的\r\n等

    string imagedata;imagedata = “dudau\r\ndadafca\r\n” CString Image; Image = imagedata.c_str(); Image. ...

  6. Git笔记之初识vi编辑器

    1.vi编辑器 如同Windows下的记事本,vi编辑器是Linux下的标配,通过它我们可以创建.编辑文件.它是一个随系统一起安装的文本编辑软件. vi编辑器提供了3种模式,分别是命令模式.插入模式. ...

  7. CentOS 64位系统 yum安装32位软件包的方法

    //假如你要安装libjpeg的32位版本 1.查询具体的32位版本,然后安装 yum search libjpeg.i686 yum -y install libjpeg.i386 2.一劳永逸的方 ...

  8. [洛谷P4918]信仰收集

    题目背景 随着各种势力的迁入,守矢神社丧失了不少信仰现在,为了挽回香火日益惨淡的神社,八坂神奈子派遣神社的风祝早苗去人类村落收集信仰 题目描述 你可以将村落看成一个m个点的有向无环图(编号从1−m), ...

  9. hibernate关联非主键注解配置

    现在有两张表:一张t_s_user用户表和t_s_user_serial_number用户序号表 CREATE TABLE `t_s_user` ( `id` ) NOT NULL, `email` ...

  10. 使用vs的时候,遇到这个:当前不会命中断点 还没有为该文档加载任何符号

    一 http://stackoverflow.com/questions/2155930/fixing-the-breakpoint-will-not-currently-be-hit-no-symb ...