hdu 3401 Trade 【单调队列+dp】

本文介绍了一种基于动态规划的股票交易策略算法,通过优化DP状态转移方程,利用单调队列来解决股票买卖问题,使得算法的时间复杂度得到有效控制。



点击打开链接



题意:

          一个人有很多钱(无限多),他想搞股票再赚钱,给你接下来d天的股市行情,问他最多能赚多少钱。

         首先他每隔w天才能交易,

         每天有四个变量,ap,bp,as,bs  分别代表今天股票买入价格,卖出价格,购买最大数量,卖出最大数量。

          

题解:


        应该很容易都想到了dp,推出方程,dp[i][j], 代表前i天身上j支股票的最大盈利值。

       1.今天不买也不买,dp[i][j]=max(dp[i][j],dp[i-1][j]);

       2.今天买入, dp[i][j]=max(dp[i][j],dp[i-w-1][k]-ap[i]*(j-k));

       3.今天卖出, dp[i][j]=max(dp[i][j],dp[i-w-1][k]+bp[i]*(k-j));

       O(d*d*maxp*maxp)  这样会超时,

      只考虑买入,f(i)= dp[i][k]+k*ap[i];

       维护一个单调队列  f(x)=max(f(k)),(j-as[i]<=k<=j);

       同理考虑卖出。

令f(x)=max(f(k)), (j<=k<=j+bs[i]);

#include<bits/stdc++.h>

#define ll long long
using namespace std;
const int maxn=2005;
const int inf=1e9;
inline int read(){int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar())
if(c=='-')f=-1;for(;isdigit(c);c=getchar())x=x*10+c-'0';return x*f;}
int ap[maxn],bp[maxn],as[maxn],bs[maxn];
int dp[maxn][maxn];
int d,maxp,w,head,tail;
struct node{
    int val;
    int x;
}que[maxn],t;
int main(){
    int ca=read();
    while(ca--){
        int ans=0;
        d=read();maxp=read();w=read();
        for(int i=1;i<=d;++i){
            ap[i]=read();bp[i]=read();as[i]=read();bs[i]=read();
        }
        for(int i=0;i<=d;++i)
            for(int j=0;j<=maxp;++j)
                dp[i][j]=-inf;
        for(int i=1;i<=w+1;++i)//可以交易之前都先买入
            for(int j=0;j<=min(as[i],maxp);++j)
                dp[i][j]=-ap[i]*j;
        for(int i=2;i<=d;++i){
            for(int j=0;j<=maxp;++j) //不买也不卖
                dp[i][j]=max(dp[i][j],dp[i-1][j]);
            if(i<=w+1) continue;//初次交易肯定要在w+1天之后。
            head=1;tail=0;
            for(int j=0;j<=maxp;++j){//买入
                t.x=j;
                t.val=dp[i-w-1][j]+ap[i]*j;
                while(tail>=head&&t.val>que[tail].val) tail--;
                que[++tail]=t;
                while(tail>=head&&que[head].x<j-as[i]) head++;
                if(head<=tail) dp[i][j]=max(dp[i][j],que[head].val-ap[i]*j);
            }
            head=1;tail=0;
            for(int j=maxp;j>=0;--j){//卖出
                t.x=j;
                t.val=dp[i-w-1][j]+bp[i]*j;
                while(tail>=head&&t.val>que[tail].val) tail--;
                que[++tail]=t;
                while(tail>=head&&que[head].x>j+bs[i]) head++;
                if(head<=tail) dp[i][j]=max(dp[i][j],que[head].val-bp[i]*j);
            }
        }
        for(int j=0;j<=maxp;++j)
            ans=max(ans,dp[d][j]);
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值