首页 > 其他分享 >20230705-动态规划DP 2

20230705-动态规划DP 2

时间:2023-07-19 22:56:26浏览次数:48  
标签:20230705 head le 容器 maxn DP 动态 dp

20230705

单调队列优化DP

HDU 3401 Trade

题目大意

传送门
有T天,第i天买股票花Api元,卖股票花Bpi元,最多能买Asi股,
能卖Bsi股。任何时候股票持有量不得超过MaxP,且两个交易日至
少要间隔W天。
若开始时有无限块钱,最后最多能赚多少钱?
(你都有无限块钱了怎么赚都不会增加啊)
0 <= W < T <= 2000, 1 <= MaxP <= 2000
1<=BPi<=APi<=1000, 1<=ASi,BSi<=MaxP

Solution

差一点点就自己写出来啦
很明显,我们考虑写DP
先令\(dp[i][j]\)表示现在是第\(i\)天,手上有\(j\)张股票时最大赚的钱数
那么
\(dp[i][j]=max\left\{\begin{matrix} dp[i-1][j] \\ dp[i-W-1][k]-(j-k)* Ap[i] \\ dp[i-W-1][k]+(k-j)* Bp[i] \end{matrix}\right.\)
三种情况分别对应什么都不做、买股票和卖股票
而由于\(dp[i-W-1][k]\)记录的是\(i-W-1\)之前的最优解
所以我们不用再枚举\(i-W-1\)之前的解了

现在考虑优化掉\(k\)这一维
由于\(k\)表示的是手上有多少张股票
所以\(dp[i-W-1][k]\)是单调不下降的
这样就可以考虑用单调队列来维护

先来考虑买股票的情况
在枚举每一个\(i\)的过程中
对于当前枚举到的\(j\)
我们想要\(O(1)\)求得在\(dp[i-W-1][0 \sim j]\)中
使得\(dp[i-W-1][k]+k* Ap[i]\)最大的这个数\(k\)
最后更新dp时减去\(j* Ap[i]\)即可
考虑用单调队列来维护
由于\(dp[i-W-1][j]\)是可以直接转移到\(dp[i][j]\)的
而\(j\)又是不断增大的
在每一次入队时
我们考虑在这个状态下\(dp[i-W-1][j]\)与队尾的所计算的答案比较是否更优
如果更优我们就弹出队尾
这样就可以保证单调队列的正确性
而队首出队就只用判断是否可以转移到\(j\)即可

再来考虑卖股票的情况
由于我们需要的是\(k-j\)
所以需要倒序枚举
其他的操作和买股票基本一致

注意:
队列初始化时不能出错\(head=1,tail=0\)!!!

H_W_Y-Coding
#include <bits/stdc++.h>
using namespace std;

const int maxn=2005,inf=0x3f3f3f3f;
int t,T,W,mxp,Ap[maxn],Bp[maxn],As[maxn],Bs[maxn];
int dp[maxn][maxn],ans=0,q[maxn*2],head,tail;

inline int read(){
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
  while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
} 

int main(){
  /*2023.7.5 H_W_Y HDU3401 Trade 单调队列优化DP*/ 
  t=read();
  while(t--){
    T=read();mxp=read();W=read();
	for(int i=1;i<=T;i++) {
	  Ap[i]=read();Bp[i]=read();As[i]=read();Bs[i]=read();
	  for(int j=0;j<=mxp;j++) dp[i][j]=dp[0][j]=-inf;
	}
	for(int i=1;i<=W+1;i++)
	  for(int j=0;j<=min(As[i],mxp);j++)
	  	dp[i][j]=-j*Ap[i];
    dp[0][0]=0;
    for(int i=1;i<=T;i++){
      for(int j=0;j<=mxp;j++) dp[i][j]=max(dp[i][j],dp[i-1][j]);
      if(i<=W+1) continue;
      head=1;tail=0;
      for(int j=0;j<=mxp;j++){
      	while(head<=tail&&q[head]+As[i]<j) head++;
      	if(q[head]<=j) dp[i][j]=max(dp[i][j],dp[i-W-1][q[head]]-(j-q[head])*Ap[i]);
      	while(head<=tail&&dp[i-W-1][q[tail]]-(j-q[tail])*Ap[i]<dp[i-W-1][j]) tail--;//如果更优 
      	q[++tail]=j;
	  }
	  head=1;tail=0;
	  for(int j=mxp;j>=0;j--){
	  	while(head<=tail&&q[head]-Bs[i]>j) head++;
	  	if(q[head]>=j) dp[i][j]=max(dp[i][j],dp[i-W-1][q[head]]+(q[head]-j)*Bp[i]);
	  	while(head<=tail&&dp[i-W-1][q[tail]]+(q[tail]-j)*Bp[i]<dp[i-W-1][j]) tail--;
	  	q[++tail]=j;
	  }
	}
	ans=-inf;
	for(int i=0;i<=mxp;i++)
	  ans=max(ans,dp[T][i]);
    printf("%d\n",ans);
  }
  return 0;
}

四边形不等式优化DP

斜率优化DP

P3195 [HNOI2008] 玩具装箱

题目大意

传送门
P教授有编号为1…N的N件玩具,第i件玩具经过压缩后变成一维长度为\(C_i\)。为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第\(i\)件玩具到第\(j\)个玩具放到一个容器中,那么容器的长度将为 \(x=j-i+Sigma(Ck)\)\(i \le K \le j\) 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为\(x\),其制作费用为\((X-L)^2\).其中\(L\)是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小。
\(1\le N \le 50000,1 \le L,C_i \le 10^7\)

Solution

有关斜率优化的专题讲解

期望与概率DP

标签:20230705,head,le,容器,maxn,DP,动态,dp
From: https://www.cnblogs.com/hewanying0622/p/17529345.html

相关文章

  • 20230703-动态规划DP 1
    20230703热身题目求长度为n的合法括号序列有多少个,对\(10^9+7\)取模。\(n\)为偶数,\(n\le10^6\)。Solution可以维护一个栈遇到一个左括号就加入栈而遇到右括号时就取栈顶的左括号与它配对出栈一个合法序列需要保证:最后栈为空,即所有的左括号都和有括号配对了中间不能出......
  • WordPress数据表结构
    如果是一个普通的用户,不需要了解wordpress数据库的结构。但是,如果你正在写一个插件,你应该会对wordpress如何处理它的数据和关系感兴趣。如果你已经尝试使用已经存在的wordpressapi去访问你需要的数据,但不直接访问数据库的情况下,这是不可能的,WordPress的提供WPDB的类,使这项任务变......
  • DP: 0-1背包,完全背包
    见:『一文搞懂完全背包问题』从0-1背包到完全背包,逐层深入+推导-零钱兑换-力扣(LeetCode)0-1背包:dp[i][w]=minmax(dp[i-1][w],dp[i-1][w-wi]+vi)完全背包dp[i][w]=minmax(dp[i-1][w],dp[i][w-wi]+vi)即完全背包可以是重复选。另外,通常可以简化2D数组到1D,因为......
  • Oracle的expdp导出、impdp导出命令
    expdp在源oracle所在服务器执行如下步骤:1、手动创建目录 mkdir-p/home/oracle/mydata2、将目录授权给用户 cd/home/oracle chown-Roracle:oinstallmydata3、oracle用户切换并使用管理员登陆oracle su-oracle sqlplus/assysdba4、源库创建directory createdirectorym......
  • 【dp,建模】AGC032D Rotation Sort
    ProblemLink有一个长为\(n\)的排列\(p\),给定\(A,B\),你每次可以做以下两种操作之一:选取\(l,r\),将\(p[l:r]\)循环右移,代价为\(A\);选取\(l,r\),将\(p[l:r]\)循环左移,代价为\(B\)。求将\(p\)排序所需的最小代价。\(n\le5000\)。技巧:循环移位→插入→实数坐......
  • 集群监管-USDP(智能大数据平台)
    UCloudSmartDataPlatform(简称USDP),是UCloud推出的智能化、轻量级、适用于私有化部署至客户本地的大数据基础服务平台,通过自研的USDPManager管理工具,支持用户创建大数据集群,在集群中部署Hadoop、Hive、HBase、Spark、Flink、Presto、Atlas、Ranger等众多开源大数据组件,并......
  • 7.17~7.18 DP专场
    CF1814EChainChips好久没写这种题了~~不带修时,为了让总距离和最短,考虑让相邻的车互换位置,但如果单纯这样有可能剩下一辆车,那就让相邻的三辆车换一下。发现当车的个数\(x\ge4\)时,都可以拆成\(2\)辆或\(3\)辆车。对应到边就是只能选相邻的一条边或两条边。设\(dp_i\)......
  • ThreadPoolExecutor线程池用法简介
    ThreadPoolExecutor 是Java中用于管理线程池的类,它提供了一种方便的方式来执行多线程任务。通过使用线程池,我们可以有效地管理和复用线程,提高程序的性能和资源利用率。下面是 ThreadPoolExecutor 线程池的详细用法介绍:创建线程池对象:ThreadPoolExecutorexecutor=ne......
  • 第九节 动态规划 - 1
    简介动态规划(DynamicProgramming,DP)及其解决的问题、根据其设计的算法及优化。动态规划是一种通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。由于动态规划并不是某种具体的算法,而是一种解决特定问题的方法,因此它会出现在各式各样的数据结构中,与之相关的题目......
  • 加载器、链接器、动态链接器概念
    动态链接器:共享库(sharedlibrary)是致力于解决静态库缺陷的一个现代创新产物。共享库是一个目标模块,在运行或加载时,可以加载到任意的内存地址,并和一个在内存中的程序链接起来。这个过程称为动态链接(dynamiclinking),是由一个叫做动态链接器(dynamiclinker)的程序来执行的。链接器:......