股票买卖 I
题目描述
输入描述
输出描述
输入样例1
6
7 1 5 3 6 4
输出样例1
1
输入样例2
5
7 6 4 3 1
输出样例2
0
样例说明
普普通通的一题,采用贪心解决即可。
对于每个读入的数,不断更新从当前时刻开始买入的最小值,同时更新若在当前时刻卖出能够获得的利润最大值。
当呈现样例 2 的暴跌状态时,不做任何交易为最优解。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int minn=a[1];
int ans=0;
for(int i=2;i<=n;i++){
minn=min(minn,a[i]);
ans=max(ans,a[i]-minn);
}
cout<<ans;
return 0;
}
股票买卖 II
题目描述
输入描述
输出描述
输入样例1
6
7 1 5 3 6 4
输出样例1
7
输入样例2
5
1 2 3 4 5
输出样例2
4
输入样例3
5
7 6 4 3 1
输出样例3
0
样例说明
本题比 I 代多出的条件是:可以进行多次交易,但必须在购买前卖出之前持有的股票。
显然本题仍然可用 贪心 + 单调 的方法来做,某一段下降序列的终点即为买入的最优价格,而接下来一段上升序列的终点即为卖出的最优价格,重复直至遍历完整个序列即可。同时注意 flag 标记当前手中是否持有股票。
但毕竟本系列题的终点是状态机 dp ,所以本题当然还是 dp 的好啦。
此时若单纯使用类似 LIS 的一维 dp,会发现一维 dp 所能表示的仅有天数,而无法同时标记手中是否持有股票这一状态,由此可能同时参与至多笔交易中。因此,需要新增一维以表示是否持有股票这一状态,而对于该类新增了若干维度以表示新增的若干状态的,属于状态机 dp 。
由此,对于第 i 天的状态共存在两种可能:f [ i ] [ 0 ] 或 f [ i ] [ 1 ],其中第二维的 0 表示当前手中没有股票,可以进行买入,1 表示当前手中有股票,只能进行卖出。
因此,可转移到以上两种情况的状态分别是:
① 前一天手中没有股票,并决定第二天不购买; f [ i ] [ 0 ] = f [ i - 1 ] [ 0 ]
② 前一天手中持有股票,决定在第二天卖出; f [ i ] [ 0 ] = f [ i - 1 ] [ 1 ] + w [ i ]
③ 前一天手中持有股票,并决定第二天不卖出; f [ i ] [ 1 ] = f [ i - 1 ] [ 1 ]
④ 前一天手中没有股票,决定在第二天买入; f [ i ] [ 1 ] = f [ i - 1 ] [ 0 ] - w [ i ]
其中,w [ i ] 代表第 i 天股票的价格。
而结束的状态为 f [ n ] [ 0 ] ,因为若在最后一天手中持有股票,一定不如在购买的那一日选择【不购买】的状态更优。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
int a[N];
int f[N][2];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
f[0][0]=0;
f[0][1]=-inf;
for(int i=1;i<=n;i++){
f[i][1]=max(f[i-1][1],f[i-1][0]-a[i]);
f[i][0]=max(f[i-1][0],f[i-1][1]+a[i]);
}
cout<<f[n][0];
return 0;
}
股票买卖 III
题目描述
输入描述
输出描述
输入样例1
8
3 3 5 0 0 3 1 4
输出样例1
6
输入样例2
5
1 2 3 4 5
输出样例2
4
输入样例3
5
7 6 4 3 1
输出样例3
0
样例说明
本题比 II 中新增的约束是:最多只能完成两笔交易。
显然,之前的二维 dp 已经不再能满足本题的需求,因为本题中还需要记录已经完成了多少次交易,由此不得不新增一维以 套娃的 标识新状态。 即 f [ i ] [ k ] [ 0/1 ],其中 i 表示天数,k 表示交易次数,0/1 即标识手中是否有货,显然 k 的限制条件是小于等于 2 。
对于本题中状态的转移仅需要多考虑第二维,即每次买入后令交易次数加一(因为每次买入后都会有对应的卖出操作,若一直将股票留到结束显然不是最优解)。注意枚举答案时需要枚举交易次数,因为在样例 3 中显然交易次数为 0 是比其他选择更优的。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10,inf=0x3f3f3f3f;
int a[N];
int f[N][3][2];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i = 0; i <= n; i++)
for(int j = 0; j <= 2; j++){
f[i][j][0] = -inf;
f[i][j][1] = -inf;
}
for(int i = 0; i <= n; i++)
f[i][0][0] = 0;
for(int i=1;i<=n;i++){
for(int k=1;k<=2;k++){
f[i][k][0]=max(f[i-1][k][0],f[i-1][k][1]+a[i]);
f[i][k][1]=max(f[i-1][k][1],f[i-1][k-1][0]-a[i]);
}
}
int ans=0;
for(int k=0;k<=2;k++){
ans=max(ans,f[n][k][0]);
}
cout<<ans<<endl;
return 0;
}