You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

103 lines
3.3 KiB

2 years ago
##[$AcWing$ $1058$. 股票买卖 $V$](https://www.acwing.com/problem/content/1060/)
### 一、题目描述
给定一个长度为 $N$ 的数组 $w$,数组的第 $i$ 个元素 $w_i$ 表示第 $i$ 天的股票 **价格**
* **一次买入+一次卖出** 为一笔 **合法交易**,且 **不能同时产生多笔交易**(必须在再次购买前出售掉之前的股票)
* 卖出股票后,无法在第二天买入股票(冷冻期为$1$天)
设计一个**方案**,使得总利润 **最大**
**输入格式**
第一行包含整数 $N$,表示数组长度。
第二行包含 $N$ 个不超过 $10000$ 的正整数,表示完整的数组。
**输出格式**
输出一个整数,表示最大利润。
**数据范围**
$1≤N≤10^5$
**输入样例**
```cpp {.line-numbers}
5
1 2 3 0 2
```
**输出样例**
```cpp {.line-numbers}
3
```
**样例解释**
对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出],第一笔交易可得利润 $2-1 = 1$,第二笔交易可得利润 $2-0 = 2$,共得利润 $1+2 = 3$。
### 二、题目分析
**线性** 的方式 **动态规划**,考虑第 $i$ 天 的状态,需要记录的参数有哪些:
第 $i$ 天的 **决策状态**
$j=0:$ 当前没有股票,且,不处于冷冻期 **空仓**
$j=1:$ 当前有股票 **持仓**
$j=2:$ 当前没有股票(当天卖出了股票),处于 **冷冻期**
> **注意** **冷冻期** 状态,现实含义是指当天卖出了股票,**后一天是没法交易**
### 三、状态机模型分析
<center><img src='https://cdn.acwing.com/media/article/image/2021/07/03/55909_f22fdff4db-IMG_5D88B9FE2880-1.jpeg'></center>
如果第 $i$ 天是 **空仓** $j=0$ 状态,则 $i-1$ 天可能是 **空仓** $j=0$ 或 **冷冻期** $j=2$ 的状态
如果第 $i$ 天是 **持仓** $j=1$ 状态,则 $i-1$ 天可能是 **持仓** $j=1$ 状态 或 **空仓** $j=0$ 的状态,在第$i$天选择了**买入**
如果第 $i$ 天是 **冷冻期** $j=2$ 状态,则 $i-1$ 天只可能是 **持仓** $j=1$ 状态,在第 $i$ 天选择了 **卖出**
#### 闫氏DP分析法
**状态表示**$f[i][j]$属性: 考虑前 $i$ 天股市,当前第 $i$ 天的状态是 $j$ 的方案
**状态表示**$f[i][j]$集合: $Max$(方案的总利润)
**状态计算**$f[i][j]$
$$ \large
\left\{\begin{array}{l} f[i][0]=max(f[i-1][0],f[i-1][2])
\\ f[i][1]=max(f[i-1][1],f[i-1][0]-w_i)
\\ f[i][2]=f[i-1][1]+w_i
\end{array}\right.
$$
**初始状态** $f[i][0]=0$ , 其它的状态初始化为$-INF$
**目标状态** $f[n][j]$其中$j=0,2$
#### $Code$
时间复杂度: $O(N)$
空间复杂度: $O(N)$
```cpp {.line-numbers}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
int w[N];
int f[N][3];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
//无法判定或肯定不合理的
memset(f, -0x3f, sizeof f);
//这些状态是合理的
for (int i = 0; i <= n; i++) f[i][0] = 0;
//开始进行状态转移
for (int i = 1; i <= n; ++i) {
f[i][0] = max(f[i - 1][0], f[i - 1][2]);
f[i][1] = max(f[i - 1][1], f[i - 1][0] - w[i]);
f[i][2] = f[i - 1][1] + w[i];
}
printf("%d\n", max(f[n][0], f[n][2]));
return 0;
}
```