标签:最优 pre 答案 问题 return 重叠 直接 out 处理
主要不好想到定义问题状态,一开始想枚举第一次股票交易的卖出时间【这样O(1)处理第一次买入时间,logN处理第二次最大利益(第二次交易实际上是取最大值,所以可以用堆维护)】,但T*N*logN就tle了。
正解是dp1(i)代表1-i天一次交易的最大收益;再dp2(i)代表i-n天的最大收益。
以dp1(i) = max( dp1(i-1) , a[i]-prev[i] ),prev是最小前缀,dp2同理。
这样O(n)做完。
难点在于怎么定义这个状态,因为一般来说会像我那么想i得是能提供一些信息的东西,而这里的dp(i)却不代表一定要在第i天做什么。所以这里的动态规划融合了【分治】的思想,要交易两次是吧,而且两次的时间不能有重叠,所以我就分开看。所以我们是从答案长什么样子入手,知道他们是分开的。那么一定能写成1-i天最大收益+i-n天最大收益的形式(不然他就不是最优解了),由此定义出的状态。所以像我之前对于dp的理解一样,我们定义状态如果直接定义出来了那么很好,不然的话要得到一些性质,并从性质入手去描述状态。
1 #include<iostream> 2 using namespace std; 3 4 int a[100005],Prev[100005],post[100005],dp1[100005],dp2[100005]; 5 //dp1[i] 1-i的最大收益 6 //dp2[i] i-n的最大收益 7 int main(){ 8 int t; cin>>t; 9 while(t--){ 10 int n,ans=0; cin>>n; 11 for(int i=1;i<=n;i++) scanf("%d",a+i); 12 for(int i=1;i<=n;i++) dp1[i]=dp2[i]=0; 13 14 Prev[1]=a[1]; for(int i=2;i<=n;i++) Prev[i]=min(Prev[i-1],a[i]);//在第i天能买股票的最低价 15 post[n]=a[n]; for(int i=n-1;i>=1;i--) post[i]=max(post[i+1],a[i]);//第i天到第n天能卖出的最大值 16 17 for(int i=2;i<=n;i++) dp1[i]=max(dp1[i-1],a[i]-Prev[i]); 18 for(int i=n-1;i>=1;i--) dp2[i]=max( dp2[i+1],post[i]-a[i] ); 19 for(int i=1;i<=n;i++) ans=max(ans,dp1[i]+dp2[i]); 20 21 cout<<ans<<endl; 22 } 23 24 return 0; 25 }
POJ 8464 股票买卖 【dp】【北大ACM/ICPC竞赛训练】
标签:最优 pre 答案 问题 return 重叠 直接 out 处理
原文地址:https://www.cnblogs.com/ZhenghangHu/p/9359307.html