zoukankan      html  css  js  c++  java
  • POJ 8464 股票买卖 【dp】【北大ACM/ICPC竞赛训练】

     主要不好想到定义问题状态,一开始想枚举第一次股票交易的卖出时间【这样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的理解一样,我们定义状态如果直接定义出来了那么很好,不然的话要得到一些性质,并从性质入手去描述状态。

    ===2018.9.6===

    又看了一遍这题,这题算是陪伴了我时间最久的题之一了啊。记得刚学dp的时候就是这题死活做不出来,直到暑假ACM课上做会,再到现在重新看。

    虽然这一次看还是没做出来。。

    主要是因为这题不是常规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 }
  • 相关阅读:
    冲刺阶段九
    冲刺阶段八
    学习进度十一
    人月神话阅读笔记01
    单词统计续
    冲刺阶段七
    冲刺阶段六
    冲刺阶段五
    bzoj1570: [JSOI2008]Blue Mary的旅行
    bzoj 1690: [Usaco2007 Dec]奶牛的旅行
  • 原文地址:https://www.cnblogs.com/ZhenghangHu/p/9359307.html
Copyright © 2011-2022 走看看