hdu3401trade【单调队列优化dp】


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
 

上午做了两个单调队列简直太机智2333

这个题是说有一神人能预测股票走向,每天已知买进一只股票花的钱ap、抛一只股票挣的钱bp、每天买的数量最大值as、每天卖股票的最大值bs,而且要求任何操作之间都得隔w天,手头的股票最多m股,问你t天之后最多能挣多少钱。就是开始的时候资本是0,欠钱买股票,问最后手里多少钱,你这么神你怎么不自己算→_→

很容易想到转移方程式:对比前一次买进股票dp[i][j]=dp[i-w-1][k]-(j-k)*ap  抛出股票dp[i][j]=dp[i-w-1][k]+(j-k)*bp  dp数组表示i天,手头有j支股票时赚的钱,单看这个方程时间复杂度达到三次方,用单调队列优化能降一维,具体操作呢?其实我没懂为啥要这么替换,应该是套路吧。对于抛出股票的行为,设tmp=dp[k][j]+bp*j,维护v[]数组作为单调队列,。j从m遍历到0,每次计算tmp插入单调队列中,这个操作说起来很纠结,也可能是我想错了,欢迎指正,插入队列时j的意义在于将上一次的值插入,然后取队首元素作为最大值,等到dp的递推就是求得当前的最大值,然后因为是卖出去,所以遍历是从大到小,我们设的v[]与实际的dp[]数组相差-bp*j,我们维护单调队列的意义在于每次及时找到当前的最大值嘛,递推dp的时候把差的加上就好啦。还有就是控制一次性抛出的最大值:这个时候j的意义就变成是当前值了,当前的股票数量-队首元素的股票数量若大于bs,一直出队列。应该是说明白了QAQ

/*******************
hdu3401
2016.2.23
202MS	17436K	1621 B	C++
*******************/
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int t,n,maxp,w,ap,bp,as,bs,dp[2004][2004],v[2004],q[2004],l,r;
int max(int a,int b) {return a>b?a:b;}
int main()
{
   // freopen("cin.txt","r",stdin);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&maxp,&w);
        for(int i=1;i<=w+1;i++)
        {
            scanf("%d%d%d%d",&ap,&bp,&as,&bs);
            for(int j=0;j<=maxp;j++)
            {
                if(j<=as)dp[i][j]=-j*ap;
                else dp[i][j]=-1e9;
                if(i>1) dp[i][j]=max(dp[i-1][j],dp[i][j]);
            }
        }
        for(int i=w+2;i<=n;i++)
        {
            scanf("%d%d%d%d",&ap,&bp,&as,&bs);
            int k=i-w-1;
            l=0,r=-1;//buy
            for(int j=0;j<=maxp;j++)
            {
                int tmp=dp[k][j]-ap*(maxp-j);//dp下标咋还能写错
                while(l<=r&&v[r]<tmp) r--;
                q[++r]=j;
                v[r]=tmp;
                while(j-q[l]>as) l++;//除去的是差值不满足条件的,天数条件已经控制
                dp[i][j]=max(dp[i-1][j],v[l]+ap*(maxp-j));
            }
            //sell
            l=0,r=-1;
            for(int j=maxp;j>=0;j--)
            {
                int tmp=dp[k][j]+bp*j;
                while(l<=r&&v[r]<tmp) r--;
                q[++r]=j;
                v[r]=tmp;
                while(q[l]-j>bs) l++;
                dp[i][j]=max(dp[i][j],v[l]-bp*j);
            }
        }
        printf("%d\n",dp[n][0]);
    }
    return 0;
}


你可能感兴趣的:(优化,dp,单调队列)