你是一个股神,可以预测未来n天股票的价格,你最多持有m个股票,且每次交易之后需要间隔w天再进行交易。给定未来n天的每天股票的买入价格pi,卖出价格po,买入限制mi,卖出价值mo,假设初始资金无限,求最多能赚多少钱。
DP
状态表示:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示第i天持有j股票时最多赚多少钱.
状态边界:
d
p
[
i
]
[
j
]
=
−
i
n
f
,
d
p
[
0
]
[
0
]
=
0.
dp[i][j]=-inf, dp[0][0]=0.
dp[i][j]=−inf,dp[0][0]=0.
状态转移:
- 不买不卖, d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j] = dp[i-1][j] dp[i][j]=dp[i−1][j]
- 买入, d p [ i ] [ j ] = d p [ i − w − 1 ] [ k 1 ] − ( j − k 1 ) ∗ p i dp[i][j] = dp[i-w-1][k1]-(j-k1)*pi dp[i][j]=dp[i−w−1][k1]−(j−k1)∗pi,其中 m a x ( 0 , j − m i ) < = k 1 < = j max(0,j-mi)<=k1<=j max(0,j−mi)<=k1<=j
- 卖出, d p [ i ] [ j ] = d p [ i − w − 1 ] [ k 2 ] + ( k 2 − j ) ∗ p o dp[i][j] = dp[i-w-1][k2]+(k2-j)*po dp[i][j]=dp[i−w−1][k2]+(k2−j)∗po,其中 j < = k 2 < = m i n ( m , j + m o ) j<=k2<=min(m,j+mo) j<=k2<=min(m,j+mo)
单调优化
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
w
−
1
]
[
k
1
]
+
k
1
∗
p
i
)
−
j
∗
p
i
dp[i][j]=max(dp[i-w-1][k1]+k1*pi)-j*pi
dp[i][j]=max(dp[i−w−1][k1]+k1∗pi)−j∗pi
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
w
−
1
]
[
k
1
]
+
k
2
∗
p
o
)
−
j
∗
p
o
dp[i][j]=max(dp[i-w-1][k1]+k2*po)-j*po
dp[i][j]=max(dp[i−w−1][k1]+k2∗po)−j∗po
代码
/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 2048, MOD = 1000000007;
int dp[M][M]; //dp[i][j]表示第i天持有j股票时的最大收益
int A[M], B[M]; //单调队列
int main(void)
{
#ifdef _LITTLEFALL_
freopen("in.txt","r",stdin);
#endif
int T = read();
while(T--)
{
memset(dp, 0xc0, sizeof(dp)); //负的极小值
int n=read(), m=read(), w=read(); //天数, 最大钱数, 间隔
// 初始状态
dp[0][0] = 0;
for(int i=1; i<=n; ++i)
{
int pi=read(), po=read(), mi=read(), mo=read();
for(int j=0; j<=m; ++j)
dp[i][j] = dp[i-1][j]; //不买不卖
if(i<=w+1)
{
for(int j=0; j<=mi; ++j)
dp[i][j] = max(dp[i-1][j], -j*pi); //只能买
continue;
}
int l=0, r=0; //单调队列的队头与队尾(左闭右开)
for(int j=0; j<=m; ++j) //买入转移到现在
{
int val = dp[i-w-1][j] + j*pi;
while(l<r && B[r-1]<val) r--;
A[r]=j; B[r++]=val;
while(l<r && A[l]+mi<j) l++;
dp[i][j] = max(dp[i][j], B[l]-j*pi);
}
l = r = 0;
for(int j=m; j>=0; --j) //卖出转移到现在
{
int val = dp[i-w-1][j] + j*po;
while(l<r && B[r-1]<val) r--;
A[r]=j; B[r++]=val;
while(l<r && A[l]-mo>j) l++;
dp[i][j] = max(dp[i][j], B[l]-j*po);
}
}
printf("%d\n",dp[n][0]);
}
return 0;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}