BZOJ 1855 [Scoi2010]股票交易 ——动态规划

DP方程是比较简单的,主要有三种:什么都不做、买入、卖出。

发现买入卖出都是$\Theta (n^3)$但是转移方程都是线性的,而且决策和当前的情况是分开的。

所以可以单调队列优化。

复杂度$\Theta(n^2)$

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define inf 1044266559
#define ll long long
#define mp make_pair
 
int dp[2005][2005];
int que[2005],hd,tl;
struct Day{int ap,bp,as,bs;}a[2005];
int n,mxp,w;
int main()
{
    scanf("%d%d%d",&n,&mxp,&w);
    F(i,1,n) scanf("%d%d%d%d",&a[i].ap,&a[i].bp,&a[i].as,&a[i].bs);
    memset(dp,-0x3f,sizeof dp); dp[0][0]=0;
    F(i,1,n)
    {
        F(j,0,a[i].as) dp[i][j]=max(dp[i][j],-a[i].ap*j);
        F(j,0,mxp) dp[i][j]=max(dp[i][j],dp[i-1][j]);
        if (i-w-1>=0){
            hd=1,tl=0;
            F(j,0,mxp)
            {
                while (hd<=tl&&que[hd]<j-a[i].as) hd++;
                while (hd<=tl&&dp[i-w-1][que[tl]]+que[tl]*a[i].ap<=dp[i-w-1][j]+j*a[i].ap) tl--;
                que[++tl]=j;
                dp[i][j]=max(dp[i][j],dp[i-w-1][que[hd]]-(j-que[hd])*a[i].ap);
            }
            hd=1;tl=0;
            D(j,mxp,0){
                while (hd<=tl&&que[hd]>min(j+a[i].bs,mxp)) hd++;
                while (hd<=tl&&dp[i-w-1][que[tl]]+que[tl]*a[i].bp<=dp[i-w-1][j]+j*a[i].bp) tl--;
                que[++tl]=j;
                dp[i][j]=max(dp[i][j],dp[i-w-1][que[hd]]+(que[hd]-j)*a[i].bp);
            }
        }
    }
    printf("%d\n",dp[n][0]);
}

  

posted @ 2017-04-01 10:47  SfailSth  阅读(495)  评论(0编辑  收藏  举报