设
f[i][j]
f
[
i
]
[
j
]
表示到了第
i
i
天,手里有张股票,赚到最多的钱。
如果第
i
i
天不进行交易,则可以从
f[i−1][j]
f
[
i
−
1
]
[
j
]
转移。即:
f[i][j]=f[i−1][j]
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
如果第 i i 天进行交易,则可以从 f[max(0,i−W−1)][...] f [ max ( 0 , i − W − 1 ) ] [ . . . ] 转移。
(下面设 p=max(0,i−W−1) p = max ( 0 , i − W − 1 ) )
设存在非负整数 k,h k , h 满足 k>h k > h ,
判断 h×BPi−k×APi h × B P i − k × A P i 和 −(k−h)×APi − ( k − h ) × A P i 的大小关系。
把右边拆开得到 h×APi−k×APi h × A P i − k × A P i ,由于 APi≥BPi A P i ≥ B P i 且 h>0 h > 0 ,
因此 −(k−h)×APi≥h×BPi−k×APi − ( k − h ) × A P i ≥ h × B P i − k × A P i 。
k<h k < h 时同理。因此得出:在最优情况下,一天要么不进行交易,要么只买入,要么只卖出。
所以得出第 i i 天进行交易时的转移:
f[i][j]=max(f[i][j],maxj<k≤BSi+j{f[p][k]+(k−j)×BPi})
f
[
i
]
[
j
]
=
max
(
f
[
i
]
[
j
]
,
max
j
<
k
≤
B
S
i
+
j
{
f
[
p
]
[
k
]
+
(
k
−
j
)
×
B
P
i
}
)
将等号右边 max max 里的式子拆开,得到:
maxj−ASi≤k<j{f[p][k]+k×APi}−j×APi
max
j
−
A
S
i
≤
k
<
j
{
f
[
p
]
[
k
]
+
k
×
A
P
i
}
−
j
×
A
P
i
maxj<k≤BSi+j{f[p][k]+k×BPi}−j×BPi
max
j
<
k
≤
B
S
i
+
j
{
f
[
p
]
[
k
]
+
k
×
B
P
i
}
−
j
×
B
P
i
复杂度 O(T×MaxP2) O ( T × M a x P 2 )
考虑到 j−ASi j − A S i 和 BSi+j B S i + j 随 j j 单调递增,
因此可以用单调队列分别维护和 f[p][k]+k×BPi f [ p ] [ k ] + k × B P i 的最大值。复杂度 O(T×MaxP) O ( T × M a x P ) 。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 2005, INF = 0x3f3f3f3f;
int T, maxP, W, AP[N], BP[N], AS[N], BS[N], f[N][N], He, Ta, Q[N];
bool ex[N][N];
int main() {
int i, j; T = read(); maxP = read(); W = read();
for (i = 1; i <= T; i++) AP[i] = read(), BP[i] = read(),
AS[i] = read(), BS[i] = read(); ex[0][0] = 1;
for (i = 1; i <= T; i++) {
for (j = 0; j <= maxP; j++) f[i][j] = -INF;
for (j = 0; j <= maxP; j++) if (ex[i - 1][j])
f[i][j] = f[i - 1][j], ex[i][j] = 1; int p = max(0, i - W - 1);
He = Ta = 0; for (j = 0; j <= maxP; j++) {
while (He < Ta && j - Q[He + 1] > AS[i]) He++;
if (He != Ta) f[i][j] = max(f[i][j], f[p][Q[He + 1]]
- (j - Q[He + 1]) * AP[i]), ex[i][j] = 1;
if (ex[p][j]) {
while (He < Ta && f[p][Q[Ta]] + Q[Ta] * AP[i] <
f[p][j] + j * AP[i]) Ta--; Q[++Ta] = j;
}
}
He = Ta = 0; for (j = maxP; j >= 0; j--) {
while (He < Ta && Q[He + 1] - j > BS[i]) He++;
if (He != Ta) f[i][j] = max(f[i][j], f[p][Q[He + 1]]
+ (Q[He + 1] - j) * BP[i]), ex[i][j] = 1;
if (ex[p][j]) {
while (He < Ta && f[p][Q[Ta]] + Q[Ta] * BP[i] <
f[p][j] + j * BP[i]) Ta--; Q[++Ta] = j;
}
}
}
int ans = -INF; for (i = 0; i <= maxP; i++)
if (ex[T][i]) ans = max(ans, f[T][i]); cout << ans << endl;
return 0;
}