HDU 3401 Trade 【DP+单调队列优化】

来源:互联网 发布:中医古籍数据库公司 编辑:程序博客网 时间:2024/05/22 17:46

题意

给出接下来T天每天卖出、买入股票的价格,每天买入、卖出的上限,持有的股票的总上限,并且两次股票操作之间有时间间隔,求T天之后最多能赚多少钱。

分析

很容易可以写出状态转移方程:

dp[i][j]ij

dp[i][j]=max(dp[i1][j],max(dp[pre][j+k]+BP[i]k),max(dp[pre][jk]AP[i]k))

其中0preiw1,k的范围略。以上分别对应无操作,卖出和买入。
按照转移方程,朴素的做法必然是O(n4)的。但是我们观察,由于max里面有dp[i-1][j],所以dp[i][j]是大于等于d[i-1][j]的,因此pre越大越优,所以pre可以直接取i-w-1,这样就少了一个遍历。剩下的k,根据自身的范围,维护其单调性,用单调队列优化计科。

AC代码

//POJ 3401 Trade//AC 2017-01-16 12:18:10//DP, Monotonic queue#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cctype>#include <cstdlib>#include <cstring>#include <vector>#include <set>#include <string>#include <map>#include <queue>#include <deque>#include <list>#include <sstream>#include <stack>using namespace std;#define cls(x) memset(x,0,sizeof x)#define inf(x) memset(x,0x3f,sizeof x)#define neg(x) memset(x,-1,sizeof x)#define ninf(x) memset(x,0xc0,sizeof x)#define st0(x) memset(x,false,sizeof x)#define st1(x) memset(x,true,sizeof x)#define lowbit(x) x&(-x)#define input(x) scanf("%d",&(x))#define inputt(x,y) scanf("%d %d",&(x),&(y))#define bug cout<<"here"<<endl;//#pragma comment(linker, "/STACK:1024000000,1024000000")//stack expansion//#define debugconst double PI=acos(-1.0);const int INF=0x3f3f3f3f;//1061109567-2147483647const long long LINF=0x3f3f3f3f3f3f3f3f;//4557430888798830399-9223372036854775807const int maxn=2000+100;int t;int n,MaxP,W;int AP[maxn],BP[maxn],AS[maxn],BS[maxn];int dp[maxn][maxn];int monqueA[maxn],monqueB[maxn],sa,ea,sb,eb;void insertA(int pre,int i,int x){    while(sa<ea&&dp[pre][monqueA[ea-1]]+AP[i]*monqueA[ea-1]<=dp[pre][x]+AP[i]*x)        --ea;    monqueA[ea++]=x;}void insertB(int pre,int i,int x){    while(sb<eb&&dp[pre][monqueB[eb-1]]+BP[i]*monqueB[eb-1]<=dp[pre][x]+BP[i]*x)        --eb;    monqueB[eb++]=x;}int main(){    //ios::sync_with_stdio(false);    //cin.tie(0);    #ifdef debug        freopen("E:\\Documents\\code\\input.txt","r",stdin);        freopen("E:\\Documents\\code\\output.txt","w",stdout);    #endif    //IO    scanf("%d",&t);    while(t--)    {        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);        ninf(dp);        dp[0][0]=0;        for(int i=1;i<=n;++i)        {            sa=ea=0;            sb=eb=0;            int pre=max(0,i-W-1);            for(int j=0;j<=min(MaxP,BS[i]-1);++j)                insertB(pre,i,j);            for(int j=0;j<=MaxP;++j)            {                dp[i][j]=dp[i-1][j];                insertA(pre,i,j);                if(j+BS[i]<=MaxP)                    insertB(pre,i,j+BS[i]);                while(sa<ea&&monqueA[sa]<j-AS[i])                    ++sa;                while(sb<eb&&monqueB[sb]<j)                    ++sb;                if(sa<ea)                    dp[i][j]=max(dp[i][j],dp[pre][monqueA[sa]]+AP[i]*monqueA[sa]-AP[i]*j);                if(sb<eb)                    dp[i][j]=max(dp[i][j],dp[pre][monqueB[sb]]+BP[i]*monqueB[sb]-BP[i]*j);            }        }        int res=0;        for(int i=0;i<=MaxP;++i)            res=max(res,dp[n][i]);        printf("%d\n",res);    }    return 0;}
0 0