DP颂

DP之神 圣洁美丽 算法光芒照大地

我们怀着 崇高敬意 跪倒在DP神殿

你的复杂 能让蒟蒻 试图入门却放弃

在你光辉 照耀下面 AC真心不容易

dp大概是最经久不衰 亘古不化的算法了吧.

而且有各种各样的类型 优化之类的.

一直dp都不怎么好. 而且也不太知道应该怎么提高.

基本见到不认识的dp方程就不大会推(但我会打表啊= =

所以dp还是很有的学的~

正好最近刚刚肝了计算几何, 所以就顺带搞一下斜率优化dp一类的...

单调队列优化dp

单调队列大家都会吧?

不会的先出去学一下, 这里不讲.


好的, 我们来看一下这个柿子

\[f[i]=max\{f[j]+\omega(j)\} (j\in[1..i))
\]

其中\(\omega(j)\)是一个费用函数, 一般会根据题目的不同而变化.

这个dp能做到什么复杂度呢?

首先一眼\(O(n^2)\)...

然而我们可以用一个变量记录一下之前出现过的最大值.

这样转移是\(O(1)\)的了, 总复杂度就降到了\(O(n)\).

但是如果是这样呢?

\[f[i]=max\{f[j]+\omega(j)\}(j\in[i-m,i))
\]

那就不能只维护一个变量了, 因为最大值如果出现在\(j\)的取值区间之外则转移是不合法的.

这样我们就考虑用单调队列来维护最大值, 这样转移依然可以做到\(O(1)\), 总复杂度\(O(n)\).

看道: (woc辣鸡bzoj给的什么zz数据范围, T都没给怎么做...)

这题可以写出这么一个状态转移方程

\[令f[i][j]表示第i天拥有j支股票的最大收益, \\
f[i][j]=max\left\{
\begin{matrix}
f[i-w-1][k]-ap[i]*(j-k), (k\in[j-as[i],j)) //买入\\
f[i-w-1][k]+bp[i]*(k-j),(k\in(j,j+bs[i]]) //卖出\\
f[i-1][j]//不交♂易
\end{matrix}
\right.
\]

其中不交易的情况好处理, 但是如果前面两种枚举\(k\)的话就要做到\(O(n^*maxP^2)\), 显然是过不了的, 我们必须考虑优化.

我们以买入为栗化一波柿子(因为卖出同理) :

\[f[i][j]=max\{f[i-w-1][k]-ap[i]*(j-k)\}\\
=max\{f[i-w-1][k]+ap[i]*k\}-ap[i]*j (k\in[j-as[i],j])
\]

我们令\(\omega(x)=ap[i]*x\), 而我们枚举\(i\), 就可以视为\(i\)是定值, 于是\(ap[i],as[i]\)都是定值.

我们就可以看出第二维形成了一个能用单调队列优化的柿子了.

这样优化之后复杂度成功降到了\(O(n*maxP)\), 就可以通过此题了.

根据贪心原则, 为了获得最多的现金, 手里不应该留股票, 所以用每个\(f[i][0]\)更新答案即可.

不过要注意一下边界条件... 挺扯淡的..

代码:

  1. #include <cstdio>
  2. #include <cstring>
  3. const int N=2020;
  4. const int INF=0x7fffffff;
  5. int q[N<<1],d[N<<1],h=1,t=0;
  6. int f[N][N],ap[N],bp[N],as[N],bs[N];
  7. inline int gn(int a=0,char c=0){
  8. for(;c<'0'||c>'9';c=getchar());
  9. for(;c>47&&c<58;c=getchar())a=a*10+c-48;return a;
  10. }
  11. inline int max(const int& a,const int& b){
  12. return a>b?a:b;
  13. }
  14. int main(){
  15. int n=gn(),m=gn(),w=gn(),ans=0;
  16. for(int i=1;i<=n;++i)
  17. ap[i]=gn(),bp[i]=gn(),as[i]=gn(),bs[i]=gn();
  18. memset(f,192,sizeof(f));
  19. for(int i=1;i<=n;++i){
  20. for(int j=0;j<=as[i];++j) f[i][j]=-ap[i]*j;
  21. for(int j=0;j<=m;++j) f[i][j]=max(f[i][j],f[i-1][j]);
  22. if(i>w){
  23. h=1; t=0;
  24. for(int j=0;j<=m;++j){
  25. int val=f[i-w-1][j]+j*ap[i];
  26. while(t>=h&&val>=q[t]) --t;
  27. q[++t]=val; d[t]=j;
  28. while(t>=h&&d[h]<j-as[i]) ++h;
  29. f[i][j]=max(f[i][j],q[h]-ap[i]*j);
  30. }
  31. h=1; t=0;
  32. for(int j=m;j>=0;--j){
  33. int val=f[i-w-1][j]+bp[i]*j;
  34. while(t>=h&&val>=q[t]) --t;
  35. q[++t]=val; d[t]=j;
  36. while(t>=h&&d[h]>j+bs[i]) ++h;
  37. f[i][j]=max(f[i][j],q[h]-bp[i]*j);
  38. }
  39. }
  40. ans=max(ans,f[i][0]);
  41. }
  42. printf("%d",ans);
  43. }

反正差不多就这样吧....

【笔记篇】单调队列优化dp学习笔记&&luogu2569_bzoj1855股票交♂易的更多相关文章

  1. 「学习笔记」单调队列优化dp

    目录 算法 例题 最大子段和 题意 思路 代码 修剪草坪 题意 思路 代码 瑰丽华尔兹 题意 思路 代码 股票交易 题意 思路 代码 算法 使用单调队列优化dp 废话 对与一些dp的转移方程,我们可以 ...

  2. POJ - 1821 单调队列优化DP + 部分笔记

    题意:n个墙壁m个粉刷匠,每个墙壁至多能被刷一次,每个粉刷匠要么不刷,要么就粉刷包含第Si块的长度不超过Li的连续墙壁(中间可不刷),每一块被刷的墙壁都可获得Pi的利润,求最大利润 避免重复粉刷: 首 ...

  3. 算法笔记--单调队列优化dp

    单调队列:队列中元素单调递增或递减,可以用双端队列实现(deque),队列的前面和后面都可以入队出队. 单调队列优化dp: 问题引入: dp[i] = min( a[j] ) ,i-m < j ...

  4. Parade(单调队列优化dp)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2490 Parade Time Limit: 4000/2000 MS (Java/Others)    ...

  5. 【bzoj1855】 [Scoi2010]股票交易 单调队列优化DP

    上一篇blog已经讲了单调队列与单调栈的用法,本篇将讲述如何借助单调队列优化dp. 我先丢一道题:bzoj1855 此题不难想出O(n^4)做法,我们用f[i][j]表示第i天手中持有j只股票时,所赚 ...

  6. 1855: [Scoi2010]股票交易[单调队列优化DP]

    1855: [Scoi2010]股票交易 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1083  Solved: 519[Submit][Status] ...

  7. bzoj1499: [NOI2005]瑰丽华尔兹&&codevs1748 单调队列优化dp

    这道题 网上题解还是很多很好的 强烈推荐黄学长 码风真的好看 神犇传送门 学习学习 算是道单调队列优化dp的裸题吧 #include<cstdio> #include<cstring ...

  8. 洛谷P3195 [HNOI2008]玩具装箱TOY(单调队列优化DP)

    题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具, ...

  9. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

随机推荐

  1. IntelliJ快捷键记录

    1.自动补全返回类型及变量:Ctrl+Alt+V2.大小写转换:Ctrl+Shift+U3.get/set方法快捷键:Alt+Insert4. 查看类继承关系:Ctrl+H或者Ctrl+Shift+A ...

  2. RMQ 模板题 poj 3264

    题目:点这里 题意:给一个长度n的数列,然后又Q个询问,问L   到R   中最大值与最小值的差. 分析:RMQ 的模板题. 代码: #include<stdio.h> #include& ...

  3. (数据科学学习手札61)xpath进阶用法

    一.简介 xpath作为对网页.对xml文件进行定位的工具,速度快,语法简洁明了,在网络爬虫解析内容的过程中起到很大的作用,除了xpath的基础用法之外(可参考我之前写的(数据科学学习手札50)基于P ...

  4. 装箱与拆箱(TDB)

    装箱:把值类型转换为引用类型 拆箱:把引用类型转换为值类型 只能对之前装箱的变量进行拆箱.需要强制转换.

  5. js 正则替换的使用方法

    function compress(source) { const keys = {}; ⇽--- 存储目标key source.replace( /([^=&]+)=([^&]*)/ ...

  6. lsm和lkm模块

    使用LSM Hook框架进行内核安全审计.元数据捕获,安全人员只需要按照既定的调用规范编写LKM模块,并加载进Linux内核,而不需要对system call lookup表进行任何修改 https: ...

  7. 使用vue-cli脚手架和vue-router搭建项目(一)

    之前做的项目一直比较简单,并没有引入整个路由库.今天准备练习下

  8. Ruby 环境变量

    Ruby 环境变量 Ruby 解释器使用下列环境变量来控制它的行为.ENV 对象包含了所有当前设置的环境变量列表. 变量 描述 DLN_LIBRARY_PATH 动态加载模块搜索的路径. HOME 当 ...

  9. JavaWeb学习篇之----Session&&Cookie

    今天继续来看看JavaWeb的相关知识,这篇文章主要来讲一下Session和Cookie的相关知识,首先我们来看一下Cookie的相关知识: 一.Cookie 简介: Cookie是客户端技术,服务器 ...

  10. 树形dp换根,求切断任意边形成的两个子树的直径——hdu6686

    换根dp就是先任取一点为根,预处理出一些信息,然后在第二次dfs过程中进行状态的转移处理 本题难点在于任意割断一条边,求出剩下两棵子树的直径: 设割断的边为(u,v),设down[v]为以v为根的子树 ...