dp单调性优化
跟着书上的思路学习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单调性优化的更多相关文章
- dp 单调性优化总结
对于单调性优化其实更多的是观察dp的状态转移式子的单调性 进而用优先队列 单调队列 二分查找什么的找到最优决策 使时间更优. 对于这道题就是单调性优化的很好的例子 首先打一个暴力再说. f[i][j] ...
- [NOI2009]诗人小G(dp + 决策单调性优化)
题意 有一个长度为 \(n\) 的序列 \(A\) 和常数 \(L, P\) ,你需要将它分成若干段,每 \(P\) 一段的代价为 \(| \sum ( A_i ) − L|^P\) ,求最小代价的划 ...
- Lightning Conductor 洛谷P3515 决策单调性优化DP
遇见的第一道决策单调性优化DP,虽然看了题解,但是新技能√,很开森. 先%FlashHu大佬,反正我是看了他的题解和精美的配图才明白的,%%%巨佬. 废话不多说,看题: 题目大意 已知一个长度为n的序 ...
- CF868F Yet Another Minimization Problem 分治决策单调性优化DP
题意: 给定一个序列,你要将其分为k段,总的代价为每段的权值之和,求最小代价. 定义一段序列的权值为$\sum_{i = 1}^{n}{\binom{cnt_{i}}{2}}$,其中$cnt_{i}$ ...
- BZOJ4899: 记忆的轮廓【概率期望DP】【决策单调性优化DP】
Description 通往贤者之塔的路上,有许多的危机. 我们可以把这个地形看做是一颗树,根节点编号为1,目标节点编号为n,其中1-n的简单路径上,编号依次递增, 在[1,n]中,一共有n个节点.我 ...
- 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 ...
- 2018.09.28 bzoj1563: [NOI2009]诗人小G(决策单调性优化dp)
传送门 决策单调性优化dp板子题. 感觉队列的写法比栈好写. 所谓决策单调性优化就是每次状态转移的决策都是在向前单调递增的. 所以我们用一个记录三元组(l,r,id)(l,r,id)(l,r,id)的 ...
- 单调性优化DP
单调性优化DP Tags:动态规划 作业部落链接 一.概述 裸的DP过不了,怎么办? 通常会想到单调性优化 单调队列优化 斜率优化 决策单调性 二.题目 [x] 洛谷 P2120 [ZJOI2007] ...
- [BZOJ4850][JSOI2016]灯塔(分块/决策单调性优化DP)
第一种方法是决策单调性优化DP. 决策单调性是指,设i>j,若在某个位置x(x>i)上,决策i比决策j优,那么在x以后的位置上i都一定比j优. 根号函数是一个典型的具有决策单调性的函数,由 ...
随机推荐
- 菜鸟教程之工具使用(八)——EGit禁止自动转换回车换行符
众所周知,Windows和Linux系统的回车换行是不一样的.想要进一步了解它们的可以阅读下面的介绍,不感兴趣的可以直接跳过. 产生背景 关于“回车”(carriage return)和“换行”(li ...
- [APM] 2个实例+5个维度解读APM技术
为了加深EGO会员之间的相互了解,同时也为大家提供更多线上相互学习交流的机会,EGO正式启动会员群线上分享活动.本文是根据陈靖华分享主题“APM的价值”的内容整理而成. 第二期分享嘉宾:陈靖华,EGO ...
- java中自定义注释@interface的用法
一.什么是注释 说起注释,得先提一提什么是元数据(metadata).所谓元数据就是数据的数据.也就是说,元数据是描述数据的.就象数据表中的字段一样,每个字段描述了这个字段下的数据的含义.而J ...
- 【emWin】例程十五:触摸校准实例——五点校准法
介绍: 该例程介绍如何校准4.3寸.7寸液晶显示屏.校准方法如下: 1.进入以下界面,用户可选择是否进入校准界面进行液晶校准 *点击屏幕任何地方可进入校准界面 *不采取任何操作,几秒钟后会进入触摸测试 ...
- LeetCode_832. Flipping an Image_Solution
原题链接 原题中文链接 一.题目描述 二.解题思路 题目所描述的意思是对每个数组先进行取反,并且对数组中的每个元素进行取反转换,所以一共要执行两个操作. 使用reverse函数解决水平翻转的操作: 由 ...
- @Autowired注入为null问题分析
题说明 最近看到Spring事务,在学习过程中遇到一个很苦恼问题 搭建好Spring的启动环境后出现了一点小问题 在启动时候却出现[java.lang.NullPointerException] 不过 ...
- 重定向android log
android里面的log输出以往都是在eclipse里面看,如果通过USB连接电脑,可以输出到PC上. try { //adb logcat -v threadtime > logcat.tx ...
- python socket 实现的简单http服务器
预备知识: 关于http 协议的基础请参考这里. 关于socket 基础函数请参考这里. 关于python 网络编程基础请参考这里. 一.python socket 实现的简单http服务器 废话 ...
- error: style attribute '@android:attr/windowEnterAnimation' not found.
在Project/gradle.properties中添加 android.enableAapt2=false
- 服务器中了蠕虫病毒Wannamine2.0小记
近期用户反馈某台服务器总感觉性能不是很好存在卡顿,于是今天远程上去分析. 打开任务管理器发现CPU使用率非常低,内存使用也在接受范围内(10/64G).不过我有一个偏好就是不喜欢用系统自带的任务管理器 ...