[单调队列DP] HDU3401 Trade

来源:互联网 发布:北京建筑大学网络 编辑:程序博客网 时间:2024/05/17 09:14

Trade
题意:
炒股,给出第1~t天每天的买入价格Ap[i]和卖出价格Bp[i],每天最多能买入的数量As[i]和最多能卖出的数量Bs[i]。
还有几个限制,任意时刻最多持有Pmax数量的股票,两次交易(买入或卖出)间隔至少w天,如第i天交易,那么下次至少是i+w+1天。问你第t天最大收入。
题解:
首先考虑朴素DP。
DP[i][j]表示第i天持有j股票时的最大收入。
讨论转移方程:
第i天啥也不干:
DP[i][j]=DP[i1][j]
第i天买点,显然有j>k
DP[i][j]=DP[iw1][k](jk)Ap[i],(jk<=As[i])
第i天卖点,显然有k>j
DP[i][j]=DP[iw1][k]+(kj)Bp[i],(kj<=Bs[i])
然后每天能干的事就考虑完了,接下来考虑代码实现。

for(int i = 1; i <= t; ++i){    for(int j = 0; j <= p; ++j){        int mx = -inf;        mx = max(dp[i][j], dp[i-1][j]);        if(i <= w+1) continue;        for(int k = j; k >= 0 && j-k <= As[i]; --k){            mx = max(mx, dp[i-w-1][k]-(j-k)*Ap[i]);        }        for(int k = j; k <= p && k-j <= Bs[i]; ++k){            mx = max(mx, dp[i-w-1][k]+(k-j)*Bp[i]);        }        dp[i][j] = mx;    }}

我写出来是这样的,这是个tppDP,显然过不了。
那就要想优化了。
第一个方程是O(1)的就不说了。
看第二个方程。
DP[i][j]=DP[iw1][k](jk)Ap[i]
整理一下。
DP[i][j]=DP[iw1][k]+kAp[i]jAp[i]
再令f[iw1][k]=DP[iw1][k]+kAp[i]
那么方程可以这样转化:
DP[i][j]=f[iw1][k]jAp[i]
那么转移完的结果就是
DP[i][j]=max(f[iw1][k])jAp[i],(j>k)
单调队列就是针对这样的方程进行优化的。
一般的,对于类似DP[i]=max/min(f[k])+C[j],其中Ck,都可以使用单调队列,效果是使O(N)的转移降至O(1)
代码实现上,根据维护的信息范围不同,遍历的顺序就不同。

#include<stdio.h>#include<algorithm>#include<string.h>using namespace std;const int inf = ~0u>>2;const int N = 2005;int dp[N][N]; // 第i天拥有j股票情况下的最大收入// dp[i][j] = dp[i-1][j];// dp[i][j] = dp[i-w-1][k]+k*Api-j*Api; j <= p && j-k <= Asi 买入// dp[i][j] = dp[i-w-1][k]+k*Bpi-j*Bpi; j >= 0 k-j <= Bsi 卖出//// 令 f[i-w-1][k] = dp[i-w-1][k]+k*Api// dp[i][j] = max(f[i-w-1][k]) - j*Api; j > k//// 令f[i-w-1][k] = dp[i-w-1][k]+k*Bpi// dp[i][j] = max(f[i-w-1][k]) - j*Bpi j < kint As[N], Bs[N], Ap[N], Bp[N];int top, tail;struct node{    int val, pos;    node(){}    node(int a, int b){ val = a, pos = b;}}q[N*10];int main(){    int T;    scanf("%d", &T);    while(T--){        int t, p, w;        scanf("%d%d%d", &t, &p, &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 <= p; ++j) dp[i][j] = -inf;        for(int i = 1; i <= w+1; ++i){            int up = min(p, As[i]);            for(int j = 0; j <= up; ++j){                dp[i][j] = -j*Ap[i];            }        }        for(int i = 1; i <= t; ++i){            top = tail = 0;            for(int j = 0; j <= p; ++j){                dp[i][j] = max(dp[i][j], dp[i-1][j]);                if(i <= w+1) continue;                int nf = dp[i-w-1][j]+j*Ap[i];                while(top < tail && q[tail-1].val < nf) tail--;                q[tail++] = node(nf, j);                while(top < tail && j-q[top].pos > As[i]) top++;                dp[i][j] = max(dp[i][j], q[top].val-j*Ap[i]);            }            top = tail = 0;            for(int j = p; j >= 0; --j){                dp[i][j] = max(dp[i][j], dp[i-1][j]);                if(i <= w+1) break;                int nf = dp[i-w-1][j]+j*Bp[i];                while(top < tail && q[tail-1].val < nf) tail--;                q[tail++] = node(nf, j);                while(top < tail && q[top].pos-j > Bs[i]) top++;                dp[i][j] = max(dp[i][j], q[top].val-j*Bp[i]);            }        }        int ans = 0;        for(int i = 0; i <= p; ++i) ans = max(ans, dp[t][i]);        printf("%d\n", ans);    }}
0 0
原创粉丝点击