单调队列优化DP
简明题意:你初始时有$∞$ 元钱,并且每天持有的股票不超过 $Maxp$ 。 有$T$ 天,你知道每一天的买入价格 $AP_i$ ,卖出价格 $Bp_i$, 买入数量限制 $AS_i$,卖出数量限制 $BS_i$。 并且两次交易之间必须间隔 $W$天。 现在问你 $T$ 天结束后,最大收益是多少。
我们这么来想,股票买入我们可以看作是负收入
看过数据范围,我们考虑用 $DP$ 来解决这个问题
状态设计:
我们考虑用一个二维数组,显然我们首先需要记录天数,于是第一维就是天数
题目中还有一些限制,就是我们在满足收益最大的前提下,还要满足一些条件:
1,两次交易必须间隔$w$天
2,持有的股票数不得超过给定数
第一个限制条件我们很容易就可以解决,只需要在转移的时候控制一下天数就好了,我们可以直接用$DP$的第一维解决。
第二个限制呢?显然我们需要用一个新的维来记录这个问题,也就是我们需要用第二维来记录手里有多少股票。
于是设 $f[i][j]$ 为$i$天以后拥有$j$张股票所能获得的最大收益。
状态转移:
显然地存在三种大情况:
1,买股票
2,啥也不干
3,卖股票
首先对于买股票,我们又可以有两种,分别是凭空买和本来就有我再买。
啥也不干就显然了,我们就直接把前一天的搞过来就好了
麦股票显然就一种,我只能手里有的时候卖
于是我们有四种情况
case 1: 凭空买
因为直接买,我们就可以把这个初始状态直接赋值,其他的搞成 $-inf$.
$f[i][j]=-ap_i \times j \ ,\ ( 0\le j \le as_i)$
case 2:不买也不卖
直接把上一天的继承过来就可以了
$f[i][j]=max(f[i][j],f[i-1][j]),\ ( 0\le j \le maxp)$
case 3: 在之前的基础买股票
首先关于上面的问题 $1$,我们要满足之间间隔 $w$天,也就是上一次交易一定是在 $i-w-1$天的时候。
为什么我们一定在这一天进行交易?原因是我们在上一个 $case$ 中就解决了这个问题,我们已经把之前某一天以前的最优答案转移到了这一天,所以就不需要考虑以前的天数了,在这一天转移一定是比以前任何一天转移都要优的。
我们已知在第 $i$ 天拥有 $j$ 张股票,假设在第 $i-w-1$ 天有 $k$ 张股票。
$k$ 显然要比 $j$ 小,因为我们要买入,还有一个限制,我们一天最多买 $as_i$ 张,于是我们的 $k$ 的下线就是 $j-as_i$ 。
交易一共买入了 $j-k$ 张股票,要花 $(j-k) \times ap_i $ 元
那么方程就显而易见了:
$f[i][j]=max(f[i-w-1][k]-(j-k) \times ap_i) \ ,\ (j-as_i \le k \le j)$
case 4:卖股票
这个情况和上面那个很类似,但是略有不同。
这次因为要卖股票,所以 $k>j$,并且$k \le j+bs_i$.
本次交易卖出了 $k-j$ 张股票,赚钱 $(k-j) \times bp_i$ 元。
方程:
$f[i][j]=max(f[i-w-1][k]+(k-j) \times bp_i) \ ,\ (j \le k \le j+bs_i)$
优化:
对于 $case\ 3$ 和 $case\ 4$ ,如果我们直接计算,可以发现复杂度大概是 $O(n \times maxp ^2 )$ 的,妥妥的 $T$ 飞。
仔细观察式子:
$case\ 3:$
$f[i][j]=max(f[i-w-1][k]-(j-k) \times ap_i) \ ,\ (j-as_i \le k \le j)$
$case\ 4:$
$f[i][j]=max(f[i-w-1][k]+(k-j) \times bp_i) \ ,\ (j \le k \le j+bs_i)$
先来看$case\ 3$, 我们把括号拆开,得:
$f[i][j]=max(f[i-w-1][k]-j \times ap_i +k \times ap_i) \ ,\ (j-as_i \le k \le j)$
发现其中有一项是不带 $k$ 的,我们把它提出来,得:
$f[i][j]=max(f[i-w-1][k]+k \times ap_i)-j
\times ap_i \ ,\ (j-as_i \le k \le j)$
在给定 $i,j$的时候,只有一个变量 $k$ ,也就是只有$k$ 的取值会影响答案。并且在 $j$ 的循环恰当的时候, $k$ 是具有平移关系的。
或者换句话说:这是符合单调性优化的条件的。
同样的,$case\ 4$ 我们同样可以得出类似的式子:
$f[i][j]=max(f[i-w-1][k]+k \times bp_i)-j \times bp_i \ ,\ (j \le k \le j+bs_i)$
于是我们使用单调队列,每次排除过期元素,然后补上新的选择,最后从对头取出最优解更新即可。
之后就是关于 $j$ 的循环顺序问题,我们要保证上一个状态已经有了。
对于 $case \ 3$ ,我们需要用到 $(j-k)$ 的状态,于是需要正序先算出小的。
对于 $case \ 4$ ,我们需要用到 $(k-j)$ 的状态,于是需要倒叙先算出大的。
于是 $case\ 3$ 正序, $case \ 4$ 倒序。
要说的就这么多了
CODE:
|
总结:
1,对于决策转移时,有明显单调性的情况,对于状态移动时,转移决策重复度较大。都可用单调队列优化。(滑动窗口)
2,对于单调性要主动发现,主动往那方面想