[SCOI2010] 股票交易

题目描述:

赚大钱钱

题目分析:

很明显是个DP,先设计状态.
DP[i][j]为第i天手里有j张股票能赚到的最多的钱.
初始化 DP[i][j]=ap[i]j D P [ i ] [ j ] = − a p [ i ] ∗ j
转移:
1DP[i][j]=max(DP[i][j],DP[i1][j] 1 : D P [ i ] [ j ] = m a x ( D P [ i ] [ j ] , D P [ i − 1 ] [ j ] //选择不买不卖
2DP[[i][j]=max(DP[iw1][k]ap[i](jk))(jas[i]<=k<=j1) 2 : D P [ [ i ] [ j ] = m a x ( D P [ i − w − 1 ] [ k ] − a p [ i ] ∗ ( j − k ) ) ( j − a s [ i ] <= k <= j − 1 ) //买入
3:DP[i][j]=max(DP[iw1][k]+bp[i](kj))(j+1<=k<=j+bs[i]) 3 : D P [ i ] [ j ] = m a x ( D P [ i − w − 1 ] [ k ] + b p [ i ] ∗ ( k − j ) ) ( j + 1 <= k <= j + b s [ i ] ) //卖出
转移 O(NMaxp2) O ( N ∗ M a x p 2 )
T成SB了
考虑如何优化
我们把上面的 2 3 式子改写一下
f[i][j]=max(f[iw1][k]+kap[i])ap[i]j 买 入 : f [ i ] [ j ] = m a x ( f [ i − w − 1 ] [ k ] + k ∗ a p [ i ] ) − a p [ i ] ∗ j
f[i][j]=max(f[iw1][k]+kbp[i])bp[i]j 卖 出 : f [ i ] [ j ] = m a x ( f [ i − w − 1 ] [ k ] + k ∗ b p [ i ] ) − b p [ i ] ∗ j
括号里面的式子 我们是可以通过维护一个单调递减的队列来O(1)进行取最优值的
优化掉了一层的Maxp
转移 O(NMaxp) O ( N ∗ M a x p )

题目链接:

BZOJ 1855
Luogu 2569

Ac 代码:

#include <cstdio>
#include <iostream>
#include <cstring>
int dp[2001][2001];
int n,w,maxp,ap[2001],bp[2001],as[2001],bs[2001];
int dl[3000]; 
int main()
{
    scanf("%d%d%d",&n,&maxp,&w);
    for(int i=1;i<=n;i++)
    scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
    memset(dp,128,sizeof(dp));
    for(int i=1;i<=n;i++) dp[i][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=as[i];j++) dp[i][j]=-ap[i]*j;
        for(int j=0;j<=maxp;j++) dp[i][j]=std::max(dp[i][j],dp[i-1][j]);
        if(i-w-1>0)
        {
            int head=1,tail=0;
            for(int j=0;j<=maxp;j++)
            {
                while(head<=tail&&dl[head]<j-as[i]) head++;//股票购买上限
                while(head<=tail&&dp[i-w-1][j]+ap[i]*j>=dp[i-w-1][dl[tail]]+ap[i]*dl[tail]) tail--;
                dl[++tail]=j;
                dp[i][j]=std::max(dp[i][j],dp[i-w-1][dl[head]]-ap[i]*(j-dl[head]));
            }
           head=1,tail=0;
           for(int j=maxp;~j;j--)
           {
                while(head<=tail&&dl[head]>j+bs[i]) head++;//股票抛售上限
                while(head<=tail&&dp[i-w-1][j]+bp[i]*j>=dp[i-w-1][dl[tail]]+bp[i]*dl[tail]) tail--;
                dl[++tail]=j;
                dp[i][j]=std::max(dp[i][j],dp[i-w-1][dl[head]]+bp[i]*(dl[head]-j));
           }
        }
    }
    int ans=0;
    for(int i=0;i<=maxp;i++) ans=std::max(ans,dp[n][i]);
    printf("%d\n",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值