「SCOI2010」股票交易 - 背包 DP + 单调队列
题意描述
最近 \(\text{lxhgww}\) 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,\(\text{lxhgww}\) 预测到了未来 \(T\) 天内某只股票的走势,第 \(i\) 天的股票买入价为每股 \(AP_i\),第 \(i\) 天的股票卖出价为每股 \(BP_i\)(数据保证对于每个 \(i\),都有 \(AP_i \geq BP_i\)),但是每天不能无限制地交易,于是股票交易所规定第 \(i\) 天的一次买入至多只能购买 \(AS_i\) 股,一次卖出至多只能卖出 \(BS_i\) 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 \(W\) 天,也就是说如果在第 \(i\) 天发生了交易,那么从第 \(i+1\) 天到第 \(i+W\) 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 \(\text{MaxP}\)。
在第 \(1\) 天之前,\(\text{lxhgww}\) 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,\(T\) 天以后,\(\text{lxhgww}\) 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
\(0\leq W<T\leq 2000,1\leq\text{MaxP}\leq2000,1\leq BP_i\leq AP_i\leq 1000,1\leq AS_i,BS_i\leq\text{MaxP}\)
解题思路
本题可通过背包 DP 解决。
显然我们可以定义状态 \(f_{i, j}\),表示在第 \(i\) 天有 \(j\) 张股票所拥有的最多钱数。
于是我们可以有下列 \(3\) 中情况:
- 不买不卖:\(f_{i, j} = \max\{f_{i, j}, f_{i - 1, j}\}\)
- 买股票:\(f_{i, j} = \max\{f_{i, j}, f_{i - w - 1, k} + \text{ap}_i * (k - j)\} \quad k \in [j - \text{as}_i, j)\)
- 卖股票:\(f_{i, j} = \max\{f_{i, j}, f_{i - w - 1, k} + \text{bp}_i * (k - j)\} \quad k \in (j, j + \text{bs}_i]\)
初始状态为下列两种:
- 直接买:\(f_{i, j} = -\text{ap}_i \times j \quad j \in [0, \text{as}_i]\)
- 不买:除直接买外情况外 \(f_{i, j} = -\infty\)
但直接进行 DP 时间复杂度为 \(O(n^3)\),肯定无法通过本题。
观察状态转移方程,我们可以发现该方程可用单调队列优化。
对于状态转移方程:
\[ f_{i, j} = \max \begin{cases} f_{i - 1, j} \\ \max\{f_{i - w - 1, k} + \text{ap}_i * (k - j)\} & k \in [j - \text{as}_i, j) \\ \max\{f_{i - w - 1, k} + \text{bp}_i * (k - j)\} & k \in (j, j + \text{bs}_i] \end{cases} \]
通过简单代数变化可转化为:
\[ f_{i, j} = \max \begin{cases} f_{i - 1, j} \\ \max\{f_{i - w - 1, k} + \text{ap}_i * k\} - \text{ap}_i * j & k \in [j - \text{as}_i, j) \\ \max\{f_{i - w - 1, k} + \text{bp}_i * k\} - \text{bp}_i * j & k \in (j, j + \text{bs}_i] \end{cases} \]
由于 \(\max\{f_{i - w - 1, k} + \text{ap}_i * k\}\) 和 \(\max\{f_{i - w - 1, k} + \text{bp}_i * k\}\) 与 \(j\) 无关,故对于任何 \(j\),该式解出的值相等。于是我们可以用单调队列预处理该式。优化掉 \(k\) 这个维度,于是将复杂度优化到 \(O(n^2)\)。
代码演示
1 |
|