[bzoj1855][Scoi2010]股票交易_动态规划_单调队列

股票交易 bzoj-1855 Scoi-2010

题目大意:说不明白题意系列++...题目链接

注释:略。


想法:这个题还是挺难的。

动态规划没跑了

状态:dp[i][j]表示第i天手里有j个股票的最大获利。

转移:第i天可以选择搞事情或者什么都不干。

如果不买不卖的话,有dp[i][j]=dp[i-1][j]

如果选择买入,dp[i][j]=dp[i-w-1][k]-ap[i](j-k)|k>=j-as[i]

如果选择卖出,dp[i][j]=dp[i-w-1][k]+bp[i](k-j)|k<=j+bs[i].

然后,我们以k为时间戳信息,dp[i-w-1][k]+ap[i][k]为权值信息维护单调队列(以买入为例)即可。

最后,附上丑陋的代码... ...

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2010
using namespace std;
int t,maxp,w;
int f[N][N];
int q[N];
struct node
{
    int ap,bp,as,bs;
}a[N];
int main()
{
    scanf("%d%d%d",&t,&maxp,&w);
    for(int i=1;i<=t;i++)
    {
        scanf("%d%d%d%d",&a[i].ap,&a[i].bp,&a[i].as,&a[i].bs);
    }
    memset(f,-0x3f,sizeof(f));
    for(int i=1;i<=t;i++)
    {
        for(int j=0;j<=a[i].as;j++) f[i][j]=-a[i].ap*j;
        for(int j=0;j<=maxp;j++) f[i][j]=max(f[i][j],f[i-1][j]);
        if(i-w-1>=0)
        {
            int head=0,tail=0;
            for(int j=0;j<=maxp;j++)
            {
                while(head<tail&&q[head]<j-a[i].as)head++;
                while(head<tail&&f[i-w-1][j]+j*a[i].ap>=f[i-w-1][q[tail-1]]+q[tail-1]*a[i].ap)tail--;
                q[tail++]=j;
                if(head<tail)f[i][j]=max(f[i][j],f[i-w-1][q[head]]-(j-q[head])*a[i].ap);
            }
            head=0,tail=0;
            for(int j=maxp;j>=0;j--)
            {
                while(head<tail&&q[head]>j+a[i].bs)head++;
                while(head<tail&&f[i-w-1][j]+j*a[i].bp>=f[i-w-1][q[tail-1]]+q[tail-1]*a[i].bp)tail--;
                q[tail++]=j;
                if(head<tail)f[i][j]=max(f[i][j],f[i-w-1][q[head]]+(q[head]-j)*a[i].bp);
            }
        }
    }
    int ans=0;
    for(int i=0;i<=maxp;i++)
    {
        ans=max(ans,f[t][i]);
    }
    printf("%d\n",ans);
}

小结: 单调队列好有意思...

posted @ 2018-07-31 09:09  JZYshuraK_彧  阅读(200)  评论(0编辑  收藏  举报