[置顶] hdu3401_分析降维_队列优化

题意:

给出未来T天股票的买进、卖出的价格的最大上限问如何获利最大。

题解:

                  不买不卖            买                       卖
     dp = max{ dp[i-1][j] , dp[x][y] - (j-y)*APi[i] , dp[x][y] + (y-j)*BPi[i] }     .....(1)
                           x<i-w, 0<j-y<MaxP       x<i-w, 0<y-j<MaxP
                           
令pre=i-w-1;
==>  dp = max { dp[i-1][j], dp[pre][k] - APi[i]*(j-k) , dp[pre][k] + BPi[i]*(k-j) } ......(2)
    为什么能推出这步呢?我们观察第一个dp方程里面有dp[i-1][j] 每次都会和这个比较那么之前的
    这个dp[i-1][j]在之前就已经和dp[i-2][t1]比较过了,那么dp[i-2][t1]之前也和dp[i-3][t2]比较
    过了,一直递归下去发现,i-w-1之前的就已经都比较过了,那么式子(1)从0——>i-w-1滚动比较就是
    多余的。由此得出式子(2)的结论。


==>  以买入为例子:dp + j*dp[pre][k] = dp[pre][k] + k*APi[i];                      ......(3)


==>  那么久可以用单调的队列去优化,因为很明显左边的值随着 k 单调递增而递增。

                  


/**
                  不买不卖            买                       卖
     dp = max{ dp[i-1][j] , dp[x][y] - (j-y)*APi[i] , dp[x][y] + (y-j)*BPi[i] }     .....(1)
                           x<i-w, 0<j-y<MaxP       x<i-w, 0<y-j<MaxP

令pre=i-w-1;
==>  dp = max { dp[i-1][j], dp[pre][k] - APi[i]*(j-k) , dp[pre][k] + BPi[i]*(k-j) } ......(2)
    为什么能推出这步呢?我们观察第一个dp方程里面有dp[i-1][j] 每次都会和这个比较那么之前的
    这个dp[i-1][j]在之前就已经和dp[i-2][t1]比较过了,那么dp[i-2][t1]之前也和dp[i-3][t2]比较
    过了,一直递归下去发现,i-w-1之前的就已经都比较过了,那么式子(1)从0——>i-w-1滚动比较就是
    多余的。由此得出式子(2)的结论。

==>  以买入为例子:dp + j*dp[pre][k] = dp[pre][k] + k*APi[i];                      ......(3)

==>  那么久可以用单调的队列去优化,因为很明显左边的值随着 k 单调递增而递增。
*/
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef __int64 lld;
#define oo 0x3f3f3f3f
#define maxn 2005
int dp[maxn][maxn];
struct NODE
{
    int p,s;
}q[maxn];
int APi[maxn],ASi[maxn];
int BPi[maxn],BSi[maxn];

int main()
{
    int W,MaxP,T,t,head,tail;
    NODE temp;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d %d",&T,&MaxP,&W);
        for(int i=1;i<=T;i++)
            scanf("%d %d %d %d",&APi[i],&BPi[i],&ASi[i],&BSi[i]);
        memset(dp,-0x3f,sizeof dp);
        for(int i=1;i<=W+1;i++)
            for(int j=0;j<=ASi[i];j++)
                dp[i][j]=-APi[i]*j;
        for(int i=2;i<=T;i++)
        {
            for(int j=0;j<=MaxP;j++)
                dp[i][j]=max(dp[i][j],dp[i-1][j]);
            int pre=i-W-1;
            if(pre<=0) continue;

            head=tail=0;
            for(int j=0;j<=MaxP;j++)
            {
                temp.p=dp[pre][j]+j*APi[i];
                temp.s=j;
                //保证队头出来的是最优,那么如果这个temp比队尾还优,那么队尾应该删除
                while(head<tail&&q[tail-1].p<temp.p) tail--;
                q[tail++]=temp;
                while(head<tail&&j-q[head].s>ASi[i]) head++;
                dp[i][j]=max(dp[i][j],q[head].p-j*APi[i]);
            }
            head=tail=0;
            for(int j=MaxP;j>=0;j--)
            {
                temp.p=dp[pre][j]+j*BPi[i];
                temp.s=j;
                while(head<tail&&q[tail-1].p<temp.p) tail--;
                q[tail++]=temp;
                while(head<tail&&q[head].s-j>BSi[i]) head++;
                dp[i][j]=max(dp[i][j],q[head].p-j*BPi[i]);
            }
        }
        int ans=0;
        for(int i=0;i<=MaxP;i++)
            ans=max(ans,dp[T][i]);
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(算法,dp,HDU)