ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[SCOI2010]股票交易

2019-07-12 13:55:14  阅读:330  来源: 互联网

标签:2050 int maxp free BP 股票交易 dp SCOI2010


[SCOI2010]股票交易

有t天,第i天的股票买入价格\(AP_i\),数量限制\(AS_i\);卖出价格\(BP_i\),数量限制\(BS_i\)(\(AP_i\geq 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\times AP_i+b\times BP_i\),为什么不直接买\(a-b(a-b\geq 0)\),钱的变化量\(-(a-b)\times AP_i\),或者卖\(b-a,(a-b<0)\),钱的变化量\((b-a)\times BP_i\),根据题意\(AP_i\geq BP_i\)容易知道后式子两个都要大于第一个式子,于是我们对于一天只要考虑它是买还是卖了。

接着不难有

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

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

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

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

注意到决策集合范围单调递增,可以使用单调队列,按套路跑两次单调队列即可,时间复杂度不难得知为\(O(t\times 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();
}

标签:2050,int,maxp,free,BP,股票交易,dp,SCOI2010
来源: https://www.cnblogs.com/a1b3c7d9/p/11175577.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有