跟着书上的思路学习dp的单调性优化觉得还是很容易想的。

数据范围:

dp,数据范围是百万,这应该是O(n)的算法了。

首先不难想到设f[i]表示到第i个百米所能达到的最大能量,那么f[n]即为所求。

f[i]=max(f[i],f[j]+s[i]-s[j]-cost[i]);这个地方s数组是能量的前缀和,然后发现需要多加一层循环来枚举j,这个时候就是O(n^2)的算法了。

这样的话,就只有40分了,毕竟看分做题。这分给的还是很良心的。

考虑优化首先我们发现状态转移方程可以这样变f[i]=max{f[j]-s[j]}+s[i]-cost[i];我们这需要找到一个最大的f[j]-s[j]的即可

且f[j]还必须>=cost[i];因为这是判断能否调到也就是一个状态合法与否。

这样我们就可以维护一个双端队列来维护了!队首永远最优至于合法否我们需要小小的判断一下。

#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<ctime>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<vector>
#include<queue>
#include<deque>
#include<map>
#include<stack>
#include<set>
#include<bitset>
#include<cstdlib>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(int x)
{
if(x==){putchar('');putchar('\n');return;}
if(x<){putchar('-');x=-x;}
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const int MAXN=;
int v[MAXN],cost[MAXN];
int f[MAXN];//f[i]表示前i百米所能得到的最大能量
int q[MAXN],h=,t=;
int n,m;
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();f[]=m;
for(int i=;i<=n;i++)
{
v[i]=read();
cost[i]=i*;
v[i]+=v[i-];
}
q[h]=;
for(int i=;i<=n;i++)
{
while(f[q[h]]<cost[i])h++;//题目中给出保证一定能吃完,所以这个地方不需要加h<t
f[i]=f[q[h]]-cost[i]-v[q[h]]+v[i];
while(f[q[t]]-v[q[t]]<f[i]-v[i])t--;
q[++t]=i;
}
put(f[n]);
return ;
}

显然成功了呢,复杂度就是O(n)因为每个点进出队伍一次。

对于这个题目,我竟然直接手残翻开了书,看到了状态转移方程式。哎,自己没想。

其实状态转移方程也很好想,状态设为:f[i][j]表示第i个月存仓j个零件所得到的最低成本。

由此可得,f[i][j]=min{f[i-1][k]+(u[i]+j-k)*d[i]+m*k}其中j<=s,k<=j+u[i].(显然你不能把上个月的零件卖了)

由于k这个决策也需要枚举所以复杂度是O(n*s*s)的,s那么大这肯定炸啊。预期得分也是40。

搞一下优化,大括号里得到貌似都和k有关不如先展开再说。

f[i][j]=min{f[i][k]+(m-d[i])*k}+(u[i]+j)*d[i];这样的话只有f[i][k]和(m-d[i])*k和当前决策有关了,考虑维护一个最优决策那不就可以直接进行转移了么

这样的话就是O(n*s)的啊,能A。所以考虑维护一个单调队列,等等为什么要维护队列,队列中的其他值有用么,发现只要k属于它应该属于的范围之内的话,那么这个决策就一定是合法的,所以为什么要队列,直接一个值保存即可,这样每次和生成出来的值比较哪个更小不就有了最优解么。

这里就大功告成了,乌拉。

#include<bits/stdc++.h>
#include<iomanip>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<queue>
#include<deque>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<vector>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(int x)
{
if(x==){putchar('');putchar('\n');return;}
if(x<)x=-x,putchar('-');
int num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
while(num)putchar(ch[num--]);
}
const int MAXN=;
int n,m,s,p=;
int u[MAXN],d[MAXN];
int f[][];//f[i][j]表示第i个月保存j个商品所需最小费用。
int main()
{
//freopen("1.in","r",stdin);
n=read();m=read();s=read();
for(int i=;i<=n;i++)u[i]=read();
for(int i=;i<=n;i++)d[i]=read();
memset(f,,sizeof(f));
f[p][]=;
for(int i=;i<=n;i++)
{
p=p^;
int k=,ans=;
for(int j=;j<=s;j++)//枚举保存多少个商品
{
for(;k<=min(j+u[i],s);k++)//提供状态转移
//为什么最优的状态一定是ans呢?
//考虑到需要一个k值使ans最小且合法,合法那一定是<=min(j+u[i],s)
//得到ans就是最优的了,很显然吧,复杂度为n*s
ans=min(ans,f[p^][k]+(m-d[i])*k);
f[p][j]=ans+(u[i]+j)*d[i];
}
}
put(f[p][]);
return ;
}

显然的,我们发现当前状态只和上一个状态有关所以可以开滚动数组优化空间啊。这点完美意识还是需要的。

那么经过这两道题,相信单调性优化都了解的差不多了。可以深入学习一些其他优化了呢。

dp单调性优化的更多相关文章

  1. dp 单调性优化总结

    对于单调性优化其实更多的是观察dp的状态转移式子的单调性 进而用优先队列 单调队列 二分查找什么的找到最优决策 使时间更优. 对于这道题就是单调性优化的很好的例子 首先打一个暴力再说. f[i][j] ...

  2. [NOI2009]诗人小G(dp + 决策单调性优化)

    题意 有一个长度为 \(n\) 的序列 \(A\) 和常数 \(L, P\) ,你需要将它分成若干段,每 \(P\) 一段的代价为 \(| \sum ( A_i ) − L|^P\) ,求最小代价的划 ...

  3. Lightning Conductor 洛谷P3515 决策单调性优化DP

    遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...

  4. CF868F Yet Another Minimization Problem 分治决策单调性优化DP

    题意: 给定一个序列,你要将其分为k段,总的代价为每段的权值之和,求最小代价. 定义一段序列的权值为$\sum_{i = 1}^{n}{\binom{cnt_{i}}{2}}$,其中$cnt_{i}$ ...

  5. BZOJ4899: 记忆的轮廓【概率期望DP】【决策单调性优化DP】

    Description 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增, 在[1,n]中,一共有n个节点.我 ...

  6. 2018.10.14 NOIP训练 猜数游戏(决策单调性优化dp)

    传送门 一道神奇的dp题. 这题的决策单调性优化跟普通的不同. 首先发现这道题只跟r−lr-lr−l有关. 然后定义状态f[i][j]f[i][j]f[i][j]表示猜范围为[L,L+i−1][L,L ...

  7. 2018.09.28 bzoj1563: [NOI2009]诗人小G(决策单调性优化dp)

    传送门 决策单调性优化dp板子题. 感觉队列的写法比栈好写. 所谓决策单调性优化就是每次状态转移的决策都是在向前单调递增的. 所以我们用一个记录三元组(l,r,id)(l,r,id)(l,r,id)的 ...

  8. 单调性优化DP

    单调性优化DP Tags:动态规划 作业部落链接 一.概述 裸的DP过不了,怎么办? 通常会想到单调性优化 单调队列优化 斜率优化 决策单调性 二.题目 [x] 洛谷 P2120 [ZJOI2007] ...

  9. [BZOJ4850][JSOI2016]灯塔(分块/决策单调性优化DP)

    第一种方法是决策单调性优化DP. 决策单调性是指,设i>j,若在某个位置x(x>i)上,决策i比决策j优,那么在x以后的位置上i都一定比j优. 根号函数是一个典型的具有决策单调性的函数,由 ...

随机推荐

  1. 【Java】Java NIO

    NIO 为什么要使用 NIO? NIO 的创建目的是为了让 Java 程序员可以实现高速 I/O 而无需编写自定义的本机代码.NIO 将最耗时的 I/O 操作(即填充和提取缓冲区)转移回操作系统,因而 ...

  2. Oracle数据库学习(一)安装和简单使用

    新公司的新项目,需要用到Oracle数据库,所以现在便来解除此数据库,不得不说,这个数据库还这是麻烦. 安装倒是简单,就是中间会遇到各种问题. 安装步骤参考:https://blog.csdn.net ...

  3. Go_14:GoLang中 json、map、struct 之间的相互转化

    1. golang 中 json 转 struct <1. 使用 json.Unmarshal 时,结构体的每一项必须是导出项(import field).也就是说结构体的 key 对应的首字母 ...

  4. js调用winform程序(带参数)

    我们会发现,我们点击迅雷下载的时候  网页可以调用应用程序,而且连接会传入迅雷,这个是怎么做到的呢? 原理: 先注册表中添加软件的具体信息,然后通过 href 可以直接调用 1.写入注册表信息,注册, ...

  5. PHP最全笔记(一)(值得收藏,不时翻看一下)

    PHP笔记来啦~绝对干货! 以下为我以前学PHP时做的笔记,时不时的也会添加一些基础知识点进去,有时还翻出来查查. //语法错误(syntax error)在语法分析阶段,源代码并未被执行,故不会有任 ...

  6. Spark学习笔记——RDD编程

    1.RDD——弹性分布式数据集(Resilient Distributed Dataset) RDD是一个分布式的元素集合,在Spark中,对数据的操作就是创建RDD.转换已有的RDD和调用RDD操作 ...

  7. phpstrom2018

    http://www.oyksoft.com/soft/40722.html?pc=1

  8. ActiveMQ JMS 项目 基于 Maven 搭建 部署

    JAVA版本: IntellJ IDEA 版本: IntelliJ IDEA 2017.2Build #IU-172.3317.76, built on July 15, 2017Licensed t ...

  9. 《Python3网络爬虫开发实战》

    推荐:★ ★ ★ ★ ★ 第1章 开发环境配置 第2章 网页基础知识 第3章 网络爬虫基础 第4章 基本库的使用 第5章 解析库的使用 第6章 数据存储 第7章 Ajax数据爬取 第8章 动态渲染页面 ...

  10. 3、CSS属性组成和作用

    3:CSS属性组成和作用 学习目标 1.css属性和属性值的定义 2.css文本属性 3.css列表属性 4.css背景属性 5.css边框属性 6.css浮动属性 一.css属性和属性值的定义 属性 ...