【HDU】3401:Trade【单调队列优化DP】

Trade

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


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

Solution

题目大意是股票在$t$天内每天买或卖或不作为,知道每一天每一支股票的买卖价格$api,bpi$和限购或卖的量$asi,bsi$,以及每天最多持有的股票数$maxp$,还有每次交易必须隔至少$w$的限制,求最大的收益。

DP式定义为$dp[i][j]$表示在第$i$天持有$j$张股票的最大收益。

转移有三方面:

1、不作为:$dp[i][j]=dp[i-1][j]$(所以转移2、3时不用考虑$i-w-1$天前)

2、买进:$dp[i][j]=dp[i-w-1][k]-(j-k)*api=>max(dp[i-w-1][k]+k*api)-j*api$

3、卖出:$dp[i][j]=dp[i-w-1][k]+(k-j)*bpi=>max(dp[i-w-1][k]+k*bpi)-j*bpi$

观察2、3,发现max部分就是单调队列的结构,所以每次对于j找最优决策点(并且满足每天的各种限制),将$n^3$压成了$n^2$。

Code

 

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;

int t, maxp, w;
int dp[2005][2005], ap[2005], as[2005], bp[2005], bs[2005];

struct Node {
    int num, m;
} q[2005];

int main() {
    int T;
    scanf("%d", &T);
    while(T --) {
        scanf("%d%d%d", &t, &maxp, &w);
        for(int i = 1; i <= t; i ++)
            scanf("%d%d%d%d", &ap[i], &bp[i], &as[i], &bs[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 <= min(maxp, as[i]); j ++)
                dp[i][j] = -j * ap[i];
        dp[0][0] = 0;
        for(int i = 1; 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 <= 0)    continue;
            int pre = i - w - 1;
            int h = 1, t = 0;
            for(int j = 0; j <= maxp; j ++) {
                int f = dp[pre][j] + ap[i] * j;
                while(h <= t && q[t].m <= f)     t --;
                q[++ t].num = j;
                q[t].m = f;
                while(h <= t && q[h].num + as[i] < j)    h ++;
                dp[i][j] = max(dp[i][j], q[h].m - ap[i] * j);
            }
            h = 1; t = 0;
            for(int j = maxp; j >= 0; j --) {
                int f = dp[pre][j] + bp[i] * j;
                while(h <= t && q[t].m <= f)    t --;
                q[++ t].num = j;
                q[t].m = f;
                while(h <= t && q[h].num - bs[i] > j)    h ++;
                dp[i][j] = max(dp[i][j], q[h].m - bp[i] * j);
            }
        }
        int res = -inf;
        for(int i = 0; i <= maxp; i ++)    res = max(res, dp[t][i]);
        printf("%d\n", res);
    }
    return 0;
}

 

 

猜你喜欢

转载自www.cnblogs.com/wans-caesar-02111007/p/9832274.html