BZOJ 1855 [Scoi2010]股票交易 单调队列优化DP

来源:互联网 发布:淘宝店铺出售一个多少 编辑:程序博客网 时间:2024/06/06 03:19

题意:链接

方法:单调队列优化DP

解析:噢又是一道情况很多的题,然而三种更新我又落下一种导致样例不过,后来看题解才恍然- -最SB的一种更新居然忘了。

状态好想f[i][j]代表前i天有j双袜子时的最大利润。

三种更新:

第一种:f[i][j]=max(f[i][j],f[i1][j]);(然而我忘了这一种)

第二种:买入f[i][j]=max(f[i][j],f[iw1][k](jk)a[i].ap)(k>=ja[i].as);

第三种:卖出f[i][j]=max(f[i][j],f[iw1][k]+(kj)a[i].bp)(k<=max(maxp,j+a[i].bs))

然后我们观察式子,第一种更新O(1)完成,第二和第三的时候如果枚举k的话复杂度承受不了,所以考虑怎么优化,显而易见第二三种是线性的,所以考虑到队列可不可行?于是整理表达式,发现可行,则按照f[i-w-1][k]+k*a[i].ap以及f[i-w-1][k]+k*a[i].bp维护递减就可以。

代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 2010using 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);}
0 0