• [SCOI2010]股票交易


    [SCOI2010]股票交易

    有t天,第i天的股票买入价格(AP_i),数量限制(AS_i);卖出价格(BP_i),数量限制(BS_i)((AP_igeq BP_i));两次交易之间要相隔w天,所持有股票不能超过maxp,初始无限多的钱,询问可以赚到的最多钱,(0≤W<T≤2000,1≤MaxP≤2000)

    显然状态中要表现这是第几天,以及持有的股票数,决策是买还是卖,于是设(f[i][j])表示第i天持有股票j所赚最多钱数,注意递推的状态性,也就是只关注第i天持有股票j的所赚钱,会对接下来的理解大有帮助。

    注意到一个小问题,(w=0)时,就是买和卖显然可以在同一天,但是先买还是先卖,发现调换顺序并无影响,而先买再卖显然不符合生活逻辑,对于第i天,持有股票j而言,假设先买a,再卖b,所持股票变化量为a-b,同样由(f[i-1][j-(a-b)=j-a+b])转移过来,显然钱的变化量(-a imes AP_i+b imes BP_i),为什么不直接买(a-b(a-bgeq 0)),钱的变化量(-(a-b) imes AP_i),或者卖(b-a,(a-b<0)),钱的变化量((b-a) imes BP_i),根据题意(AP_igeq BP_i)容易知道后式子两个都要大于第一个式子,于是我们对于一天只要考虑它是买还是卖了。

    接着不难有

    [f[i][j]=maxegin{cases}max_{max(0,j-AS_i)leq k<j}{f[i-1][k]-(j-k) imes AP_i}\max_{j<kleq min(maxp,j+BS_i)}{f[i-1][k]+(k-j) imes BP_i}end{cases} ]

    [f[i][j]=maxegin{cases}max_{max(0,j-AS_i)leq k<j}{f[i-1][k]+k imes AP_i}-j imes AP_i\max_{j<kleq min(maxp,j+BS_i)}{f[i-1][k]+k imes BP_i}-j imes AP_iend{cases} ]

    边界:(f[0][0]=0),其余无限大

    答案:(f[t][0])

    注意到决策集合范围单调递增,可以使用单调队列,按套路跑两次单调队列即可,时间复杂度不难得知为(O(t imes maxp))

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define il inline
    #define ri register
    #define Size 2050
    using namespace std;
    int dp[2050][2050],T[2050],L,R,
        AS[2050],AP[2050],BS[2050],BP[2050];
    il void read(int&);
    template<class free>il free Min(free,free);
    template<class free>il free Max(free,free);
    int main(){
        int t,maxp,w;
        read(t),read(maxp),read(w);
        memset(dp,-2,sizeof(dp)),dp[0][0]=0;
        for(int i(1);i<=t;++i)
            read(AP[i]),read(BP[i]),read(AS[i]),read(BS[i]);
        for(int i(1),j,opt;i<=t;++i){
            for(j=0;j<=maxp;++j)dp[i][j]=dp[i-1][j];
            opt=i-w-1;if(opt<0)opt=0;L=R=1,T[1]=0;
            for(j=1;j<=maxp;++j){
                while(L<=R&&T[L]<Max(0,j-AS[i]))++L;
                dp[i][j]=Max(dp[i][j],dp[opt][T[L]]+(T[L]-j)*AP[i]);
                while(L<=R&&dp[opt][j]+j*AP[i]>=dp[opt][T[R]]+T[R]*AP[i])--R;
                T[++R]=j;
            }L=R=1,T[1]=maxp;
            for(j=maxp-1;j>=0;--j){
                while(L<=R&&T[L]>Min(maxp,j+BS[i]))++L;
                dp[i][j]=Max(dp[i][j],dp[opt][T[L]]+(T[L]-j)*BP[i]);
                while(L<=R&&dp[opt][j]+j*BP[i]>=dp[opt][T[R]]+T[R]*BP[i])--R;
                T[++R]=j;
            }
        }printf("%lld",dp[t][0]);
        return 0;
    }
    template<class free>il free Min(free a,free b){return a<b?a:b;}
    template<class free>il free Max(free a,free b){return a>b?a:b;}
    il void read(int &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
    
  • 相关阅读:
    js中的标签运动
    js的窗口坐标及拖拽
    js中滑动门的实现方法和案例
    js中的键盘事件和触摸事件
    JavaScript中的鼠标事件
    JavaScript中DOM操作之获取元素占位
    JavaScript中DOM操作之设定标签属性
    JavaScript中DOM操作文档对象模型获取标签内容
    windows10下python安装+selenium
    主体数据管理
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11175577.html
Copyright © 2020-2023  润新知