Trade
題意:
炒股,給出第1~t天每天的買入價格Ap[i]和賣出價格Bp[i],每天最多能買入的數量As[i]和最多能賣出的數量Bs[i]。
還有幾個限制,任意時刻最多持有Pmax數量的股票,兩次交易(買入或賣出)間隔至少w天,如第i天交易,那麼下次至少是i+w+1天。問你第t天最大收入。
題解:
首先考慮樸素DP。
令
討論轉移方程:
第i天啥也不幹:
第i天買點,顯然有
第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;
}
}
我寫出來是這樣的,這是個
那就要想優化了。
第一個方程是
看第二個方程。
整理一下。
再令
那麼方程可以這樣轉化:
那麼轉移完的結果就是
單調隊列就是針對這樣的方程進行優化的。
一般的,對於類似
代碼實現上,根據維護的信息範圍不同,遍歷的順序就不同。
#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 < k
int 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);
}
}