hdu3401:单调队列优化dp

第一个单调队列优化dp

写了半天,最后初始化搞错了还一直wa。。

题目大意:

炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股

且一次交易后至少要间隔w天才能再次交易,初始有0股,本金无限,求最大收益

题解:
dp[i][j]表示第 i 天,有 j 股的最大收益

状态转移 dp[i][j]=max{dp[i-1][j](不买不卖),dp[r][k]-(j-k)*pa[i](i-r>w,j-k<=na[i],买),dp[r][k]+(k-j)*pb[i](i-r>w,k-j<=nb[i],卖)}

复杂度 为 t*t*p*p

首先我们可以看出 dp[i][j]>=dp[i-1][j](不买不卖转移)

所以可以将 r 确定为 i-w-1,复杂度变为t*p*p 还是很大

然后对于买,移项有

dp[i][j]+j*pa[i]=dp[r][k]+k*pa[i]。右边与 j无关, 可见我们只需要对每一个 i 维护一个关于k的单调队列,就可以在 p时间内求出所有的dp[i][j]

复杂度降为 t*p 可以接受了

最后注意下边界条件:

1到w+1的都是从初始条件下转移的

代码:

#include <iostream>

#include <stdio.h>

#include<string.h>

#include<algorithm>

#include<string>

#include<ctype.h>

using namespace std;

#define MAXN 2000

#define inf 200000000

int na[MAXN+10],nb[MAXN+10],pa[MAXN+10],pb[MAXN+10];

int dp[MAXN+10][MAXN+10];

int t,p,w;

typedef struct Node

{

    int val,num;

}node;

typedef struct dqueue

{

    node q[MAXN*100];

    int l,r;

    bool empty()

    {

        return l==r;

    }

    void clear()

    {

        l=0;r=0;

    }

    node front()

    {

        return q[l];

    }

    void pop()

    {

        l++;

    }

    void push(node x)

    {

        if(l==r)

        {

            q[r++]=x;

            return;

        }

        if(x.val>q[l].val)

        {

            r=l;

            q[r++]=x;

            return;

        }

        for(int i=r;i>l;i--)

        {

            if(x.val<q[i-1].val)

            {

                r=i;

                break;

            }

        }

        q[r++]=x;

    }

}Dqueue;

Dqueue qa,qb;

int buy(int now,int n)

{

    node tmp;

    while(1)

    {

        tmp=qa.front();

        if(tmp.num<n-na[now])

        {

            qa.pop();

        }

        else

            break;

    }

    return tmp.val;

}

int sale(int now,int n)

{

    node tmp;

    while(1)

    {

        tmp=qb.front();

        if(tmp.num<n)

        {

            qb.pop();

        }

        else

            break;

    }

    return tmp.val;

}

void DP()

{

    for(int i=0;i<=t;i++)

    {

        for(int j=0;j<=p;j++)

        {

            dp[i][j]=-inf;

        }

    }

    node no;

    for(int i=1;i<=w+1;i++)

    {

        for(int j=0;j<=na[i];j++)

        {

            dp[i][j]=-pa[i]*j;

        }

        for(int j=0;j<=p;j++)

        {

            dp[i][j]=max(dp[i][j],dp[i-1][j]);

        }

    }

    for(int i=w+2;i<=t;i++)

    {

        qa.clear();

        qb.clear();

        int r=i-w-1;                         //上一次交易的天数

        for(int j=0;j<nb[i];j++)

        {

            no.num=j;

            no.val=dp[r][j]+j*pb[i];

            qb.push(no);

        }

        for(int j=0;j<=p;j++)

        {

            no.num=j;

            no.val=dp[r][j]+j*pa[i];

            qa.push(no);

            if(j+nb[i]<=p)

            {

                no.num=j+nb[i];

                no.val=dp[r][j+nb[i]]+(j+nb[i])*pb[i];

                qb.push(no);

            }

            dp[i][j]=max(dp[i][j],dp[i-1][j]);                   //不买

            int tmp=buy(i,j);

            dp[i][j]=max(dp[i][j],tmp-j*pa[i]);    //

            tmp=sale(i,j);

            dp[i][j]=max(dp[i][j],tmp-j*pb[i]);    //

        }

    }

}

int main()

{

    int T;

    scanf("%d",&T);

    while(T--)

    {

        scanf("%d%d%d",&t,&p,&w);

        for(int i=1;i<=t;i++)

        {

            scanf("%d%d%d%d",pa+i,pb+i,na+i,nb+i);

        }

        DP();

        int ans=0;

        for(int i=0;i<=p;i++)

        {

            ans=max(ans,dp[t][i]);

        }

        printf("%d\n",ans);

    }

    return 0;

}

 

你可能感兴趣的:(HDU)