zoukankan      html  css  js  c++  java
  • hdu3401 Trade(单调队列优化dp)

    Trade

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4734    Accepted Submission(s): 1587


    Problem Description
    Recently, lxhgww is addicted to stock, he finds some regular patterns after a few days' study.
    He forecasts the next T days' stock market. On the i'th day, you can buy one stock with the price APi or sell one stock to get BPi.
    There are some other limits, one can buy at most ASi stocks on the i'th day and at most sell BSi stocks.
    Two trading days should have a interval of more than W days. That is to say, suppose you traded (any buy or sell stocks is regarded as a trade)on the i'th day, the next trading day must be on the (i+W+1)th day or later.
    What's more, one can own no more than MaxP stocks at any time.

    Before the first day, lxhgww already has infinitely money but no stocks, of course he wants to earn as much money as possible from the stock market. So the question comes, how much at most can he earn?
     

    Input
    The first line is an integer t, the case number.
    The first line of each case are three integers T , MaxP , W .
    (0 <= W < T <= 2000, 1 <= MaxP <= 2000) .
    The next T lines each has four integers APi,BPi,ASi,BSi( 1<=BPi<=APi<=1000,1<=ASi,BSi<=MaxP), which are mentioned above.
     

    Output
    The most money lxhgww can earn.
     

    Sample Input
    1 5 2 0 2 1 1 1 2 1 1 1 3 2 1 1 4 3 1 1 5 4 1 1
     

    Sample Output
    3
     

    Author
    lxhgww
     

    Source
     

    Recommend
    lcy   |   We have carefully selected several similar problems for you:  3400 3403 3404 3402 3415 
     

    Statistic | Submit | Discuss | Note
    Hangzhou Dianzi University Online Judge 3.0
    Copyright © 2005-2017 HDU ACM Team. All Rights Reserved.
    Designer & Developer : Wang Rongtao LinLe GaoJie GanLu
    Total 0.000000(s) query 4, Server time : 2017-02-02 18:39:06, Gzip enabled

     题目大意:知道之后n天的股票买卖价格(api,bpi),以及每天股票买卖数量上限(asi,bsi),问他最多能赚多少钱。开始时有无限本金,要求任两次交易需要间隔W天以上,即第i天交易,第i+w+1天才能再交易。同时他任意时刻最多只能拥有maxp的股票,

    /*
    1. dp[i][j] 表示前 i 天手里有 j 支股票时所获得的最大收益,因为要间隔 w+1 天才能进行一次买卖
    所以前 w+1 天只能进行一个操作,那就是买操作。
    2. 关于赋初值问题,合法的状态也有可能为负值的,而且结果要取最大值
    所以非法状态要赋值为 -INFS.
    3. dp[i][j] = max(dp[i-w-1][x] - (j-x)*AP, dp[i-w-1][y] + (y-j)*BP);
     另外还有第 i 天什么都不做的情况此时为 dp[i][j] = max(dp[i][j], dp[i-1][j]).
    4. 关于转移方程,时间复杂度是很高的,所以要采取单调队列优化
    deq[],pos[] 分别放置窗口里面的最大值以及最大值所在的窗口位置。
    这里用了一个结构体的队列直接维护这两个信息
    5. 如何构造单调队列里面的转移,其实很简单例如 dp[3] = max(dp[1] + 2 * v, dp[2] + 1 * v); 
    两边同时减去 3 * v 就可以变成一个通项公式了,偏移正好。高中数学知识。
    6.推到队列优化也可以这样做,只考虑买的情况,卖的和它对称。
    dp[i][j] = max(dp[i-w-1][k]-j*ap[i]+k*ap[i]),移下项变成dp[i][j]+j*ap[i]=max(dp[i-w-1][k]+k*ap[i]),
    很明显可以把后面维护成一个递减的单调队列,每次取队首元素,使得复杂度降为O(N*P)
    */
    #include<cstdio>
    #include<cstring>
    #define MAX 2005
    #define inf 0xfffff
    #define max(a,b) ((a)>(b)?(a):(b))
    
    using namespace std;
    int T,MaxP,W;
    int APi[MAX],BPi[MAX],ASi[MAX],BSi[MAX];
    int dp[MAX][MAX];//dp[i][j]第i天持有j股的最大值
    //dp[i][j]=max{dp[i-1][j],max{dp[r][k]-APi[i]*(j-k)}(0<r<i-w,k<j),max{dp[r][k]+BPi[i]*(k-j)}(0<r<i-w,k>j)}
    struct node
    {
        int x;//存dp[i-w-1][k]+APi[i]*k或dp[i-w-1][k]+BPi[i]*k
        int p;//当前持股数
    } q[2005],temp;
    int front,back;
    int main()
    {
        int cas;
        scanf("%d",&cas);
        for(; cas--;)
        {
            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);
            for(int i=0; i<=T; ++i)
                for(int j=0; j<=MaxP; ++j)
                    dp[i][j]=-inf;
            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]);
                if(i<=W+1) continue;
                //买入
                front=back=1;
                for(int j=0; j<=MaxP; ++j)
                {
                    temp.p=j;
                    temp.x=dp[i-W-1][j]+APi[i]*j;
                    for(;front<back&&q[back-1].x<temp.x;--back);
                    q[back++]=temp;
                    for(;front<back&&q[front].p+ASi[i]<j;++front);
                    dp[i][j]=max(dp[i][j],q[front].x-APi[i]*j);
                }
                //卖出
                front=back=1;
                for(int j=MaxP; j>=0; --j)
                {
                    temp.p=j;
                    temp.x=dp[i-W-1][j]+BPi[i]*j;
                    for(;front<back&&q[back-1].x<temp.x;--back);
                    q[back++]=temp;
                    for(;front<back&&q[front].p-BSi[i]>j;++front);
                    dp[i][j]=max(dp[i][j],q[front].x-BPi[i]*j);
                }
            }
            int ans=0;
            for(int i=0;i<=MaxP;++i)
                ans=max(ans,dp[T][i]);
            printf("%d
    ",ans);
        }
        return 0;
    }
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    关于面向对象
    关于内存的划分和传引用传参数的区别
    关于目前我们专业的各种发展方向
    关于C语言底层
    关于游戏行业目前的形势
    关于jsp,javascript,php等语言
    鼠标滑动图片变大
    在Linux环境下mysql的root密码忘记解决方法
    百度网盘
    bootsrtap 主题元素
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6361462.html
Copyright © 2011-2022 走看看