跟着书上的思路学习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. js 对象数组查找元素常用方法

    let the_spec_List_Vaule = res.Data.Spec_List_Vaule.find(function(x) { return x.Spec_Item_List == pro ...

  2. linux每日命令(34):ps命令和pstree命令

    Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态的显示进程信 ...

  3. Android ShareUserId 使用总结

    今天讲一下Android里面经常看到却不太留意的知识点——ShareUserId,在Android里面每个app都有一个唯一的linux user ID,则这样权限就被设置成该应用程序的文件只对该用户 ...

  4. 【测量实战技术】Cad中导入坐标高程点并可以提取坐标带高程

    一般咱们都是导入cad的是坐标不带高程,那么怎么在cad中导入坐标高程的三维坐标呢,在不需要cass的情况下还能计算方量呢?而且还能批量提取出这些坐标高程的三维参数. 这些都是工作中非常常用的技能,不 ...

  5. pip离线安装软件包

    1. 首先一台主机上安装所有python包,然后运行如下命令下载依赖包: pip freeze > requirements pip download -r requirements 当然可以在 ...

  6. Java知多少(43)异常处理基础

    Java异常是一个描述在代码段中发生的异常(也就是出错)情况的对象.当异常情况发生,一个代表该异常的对象被创建并且在导致该错误的方法中被抛出(throw).该方法可以选择自己处理异常或传递该异常.两种 ...

  7. Netbeans 8.1 检测不到Tomcat8.5.3以上版本已经启动的Bug

    Tomcat实际上已经启动,但是netbeans就是检测不到,只要在server.xml中,找到http/1.1的connector 添加 属性 server="Apache-Coyote/ ...

  8. README.md文件编辑

    111 蜗牛图片管理系统 =============== ## 安装环境 >+ thinkphp版本: >+ php版本:.0以上 >+ 需要安装在服务器环境,免费使用 ### 特点 ...

  9. Git 解决本地远端版本冲突

    简单粗暴.... git push -u origin master -f

  10. [JS] ECMAScript 6 - Object : compare with c#

    Ref: 对象的扩展 Outline: 属性的简洁表示法 属性名表达式 方法的 name 属性 Object.is() Object.assign() 属性的可枚举性和遍历 Object.getOwn ...