1. 程式人生 > >[SCOI2010]股票交易

[SCOI2010]股票交易

-i pos push 事情 ble lin vector its down

題目大意:

網址:https://www.luogu.org/problemnew/show/P2569
大意:在接下來的T天中,每天股票有一個買入價格Api與賣出價格Bpi。
同時,每天買入股票數與賣出股票數分別不能超過Asi與Bsi。
再者,兩次股票交易之間時間間隔必須小於W天,任一時刻持股數不能超過MaxP。
那麽假設初始時錢數無限,求解T天後的最大收入值(>=0)。
\(0<=W<T<=2000,1<=MaxP<=2000\)

題目解法:

DP,狀態太顯然了:\(f[i][j]\) 表示到了第i天,持有j股的最大收入額。
轉移也很容易:
[1] \(f[i][j] = -1*j*Ap[i] ;(j<=As[i])\)

, 即從當天起直接購買。
[2] \(f[i][j] = f[i-1][j] ;\) , 即什麽都不做。
[3] \(f[i][j] = f[i-W-1][t] - (j-t)*Ap[i];(0<=t<=As[i])\),即購買股票。
[4] \(f[i][j] = f[i-W-1][t] + (t-j)*Bp[i];(0<=t<=Bs[i])\), 即賣出股票。
直接這樣轉移的時間復雜度為\(O(N^3)\)的,顯然過不去。
發現一個神奇的事情,[3]、[4]可以單調隊列優化。
不知道單調隊列優化的請戳這裏
以優化[3]為例,優化[4]是類似的。
原來的轉移方程:\(f[i][j] = f[i-W-1][t] - (j-t)*Ap[i];\)

拆開後移項:\(f[i][j] + Ap[i]*j = f[i-W-1][t] + Ap[i]*t\)
左右兩邊一模一樣,滿足單調隊列優化要求,大力跑即可。
註意在處理[4]的時候要逆序處理,原因 滑稽自己yy一下啦

具體實現代碼:

include<bits/stdc++.h>
#define maxn 2005
#define ll long long
#define gi(x) scanf("%lld",&x);
#define INF 1e16+7
using namespace std;
const ll zero = 0;

bool vis[maxn];
ll l1,l2,r1,r2,f[maxn][maxn],T,MaxP,W,Ap,Bp,As,Bs,Ans;

struct Node{ll j,f;};
struct cmp{
    bool operator ()(Node a,Node b){
        return a.f < b.f;}
};
priority_queue<Node,vector<Node>,cmp>Q;

int main(){
    gi(T); gi(MaxP); gi(W);
    for(ll i=0;i<=T;i++)for(ll j=0;j<=MaxP;j++)f[i][j]=-INF;
    f[0][0] = 0;
    for(ll i = 1; i <= T; i ++)
    {
        gi(Ap); gi(Bp); gi(As); gi(Bs);
        ll bf = max(zero,i-W-1);
        for(ll j = 0; j <= MaxP; j ++)
            f[i][j] = f[i-1][j];
        for(ll j = 0; j <= min(MaxP,As); j ++)
            f[i][j] = max(f[i][j] , -1*Ap*j);
        while(!Q.empty())Q.pop();
        for(ll j = 0; j <= MaxP; j ++){
            l1 = max(j-As,zero); r1 = j;
            while(!Q.empty() && !(l1<=Q.top().j && Q.top().j<=r1))Q.pop();
            Q.push((Node){j,f[bf][j] + Ap*j});
            f[i][j] = max(f[i][j],Q.top().f - Ap*j);
        }
        while(!Q.empty())Q.pop();
        for(ll j = MaxP; j >= 0; j --){
            l2 = j; r2 = min(j+Bs,MaxP);
            while(!Q.empty() && !(l2<=Q.top().j && Q.top().j<=r2))Q.pop();
            Q.push((Node){j,f[bf][j] + Bp*j});
            f[i][j] = max(f[i][j],Q.top().f - Bp*j);
        }
    }
    Ans = 0;
    for(ll i = 0; i <= MaxP; i ++)
        Ans = max( Ans , f[T][i] );
    cout<<Ans;
    return 0;
}

[SCOI2010]股票交易