[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();
}

转载于:https://www.cnblogs.com/a1b3c7d9/p/11175577.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值