• UESTC 880 生日礼物 --单调队列优化DP


    定义dp[i][j]表示第i天手中有j股股票时,获得的最多钱数。

    转移方程有:

    1.当天不买也不卖: dp[i][j]=dp[i-1][j];

    2.当天买了j-k股: dp[i][j]=max(dp[r][k]+(j-k)*Ap[i]); (r<i-w)

    3.当天卖了k-j股: dp[i][j]=max(dp[r][k]+(k-j)*Bp[i]); (r<i-w)

    直接转移复杂度太高,为O(n^2*Maxp^2).

    分别考虑每种转移,第一种不用管,考虑第二种。

    dp[i][j]=max(dp[r][k]+(j-k)*Ap[i])

    变换得:dp[i][j]-j*Ap[i]=dp[r][k]-k*Ap[i]。

    所以变成使dp[r][k]-k*Ap[i]最大。

    对于dp[r][k]-k*Ap[i], 因为我们已经有dp[i][k]=dp[i-1][k]的转移了,说明,dp[i][k]包含了所有dp[j][k] (j<i)的情况。 换句话说dp[i][k]是递增的。那么这里我们显然就可以直接把r换成i-w-1,于是变成了求 dp[i-w-1][k]-k*Ap[i]的最大值。

    令f[k]=dp[i-w-1][k]-k*Ap[i]) 原式变为 dp[i][j]=max(f[k])+j*Ap[i] (0=<k<j),如果再把与i相关的东西变成常数,则变成类似dp[j] = max(f[k])+c[j]形式,即变成可用单调队列优化的形式。

    维护一个单调递增队列来求f[k]。复杂度O(n*Maxp).

    因为直接令r=i-w-1,因为r>=1,所以i>w+1时才能转移,这是i<=w+1的情况需要预处理。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define Mod 1000000007
    using namespace std;
    #define N 2007
    
    struct node
    {
        int num,val;
    }que[N];
    
    int AP[N],BP[N],AS[N],BS[N];
    int dp[N][N];
    int n,Maxp,w;
    
    void init()
    {
        int i,j;
        for(i=0;i<=2000;i++)
            for(j=0;j<=Maxp;j++)
                dp[i][j] = -Mod;
        dp[0][0] = 0;
        for(i=1;i<=w+1;i++)
            for(j=0;j<=min(AS[i],Maxp);j++)
                dp[i][j] = -j*AP[i];
    }
    
    int main()
    {
        int i,j,k;
        int t,head,tail;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d%d",&n,&Maxp,&w);
            for(i=1;i<=n;i++)
                scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]);
            init();
            for(i=1;i<=n;i++)
            {
                //unbuy & unsell
                for(j=0;j<=Maxp;j++)
                    dp[i][j] = max(dp[i][j],dp[i-1][j]);
                if(i-w-1 <= 0)
                    continue;
                //buy j-k stocks
                head = 1;
                tail = 0;
                for(j=0;j<=Maxp;j++)
                {
                    int tmp = dp[i-w-1][j] + j*AP[i];
                    while(tail >= head && j-que[head].num > AS[i])
                        head++;
                    if(head <= tail)
                        dp[i][j] = max(dp[i][j],que[head].val-(j-que[head].num)*AP[i]);
                    while(tail >= head && que[tail].val+que[tail].num*AP[i] < tmp)
                        tail--;
                    que[++tail].num = j;
                    que[tail].val = dp[i-w-1][j];
                }
                //sell k-j stocks
                head = 1;
                tail = 0;
                for(j=Maxp;j>=0;j--)
                {
                    int tmp = dp[i-w-1][j] + j*BP[i];
                    while(tail >= head && que[head].num-j > BS[i])
                        head++;
                    if(head <= tail)
                        dp[i][j] = max(dp[i][j],que[head].val-(j-que[head].num)*BP[i]);
                    while(tail >= head && que[tail].val+que[tail].num*BP[i] < tmp)
                        tail--;
                    que[++tail].num = j;
                    que[tail].val = dp[i-w-1][j];
                }
            }
            int res = 0;
            for(i=0;i<=Maxp;i++)
                res = max(res,dp[n][i]);
            printf("%d
    ",res);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    莫队总结
    三、模型层(二)
    二、模型层(一)
    五、web杂项
    一. Django入门
    二、js
    一、html和css
    二十一、正则表达式
    END:小练习、涨知识
    二十、协程
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3762737.html
Copyright © 2020-2023  润新知