P2569 [SCOI2010]股票交易
题目链接
数据结构优化DP。
用(f[i][j])表示第(i)天手里还有(j)张股票的最大收益。
分四种情况转移:
直接买入,不承接之前的:
f[i][j] = -ap * j;
不卖也不买:
f[i][j] = std::max(f[i][j], f[i - 1][j]);
卖出股票:
f[i][j] = std::max(f[i][j], f[i - w - 1][k] + (k - j) * bp);
买入股票,承接之前的:
f[i][j] = std::max(f[i][j], f[i - w - 1][k] - (j - k) * ap);
为啥只能从(i - w - 1)转移过来呢?因为(i - w - 1)可能是从更前面转移过来的,比如说(i - w - 2),这样(i)其实也是从(i - w - 2)转移过来的。
可以发现,第三种和第四种情况可以把(j)提出来:
f[i][j] = max(f[i][j], std::max(f[i - w - 1][k] + k * bp) - j * bp);
f[i][j] = max(f[i][j], std::max(f[i - w - 1][k] + k * ap) - j * ap);
这样我们就可以用单调队列优化了,可以把(f[i - w - 1][k] + k * bp/ap)放入单调队列里,每次(O(1))找到最大值,总复杂度(O(n^2))。
#include <bits/stdc++.h>
inline long long read() {
long long s = 0, f = 1; char ch;
while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
return s * f;
}
const int N = 2005;
int T, P, w, l, r, ap, bp, as, bs, ans;
int p[N], f[N][N];
int main() {
T = read(); P = read(); w = read();
memset(f, -0x3f, sizeof(f));
for(int i = 1;i <= T; i++) {
ap = read(), bp = read(), as = read(), bs = read();
for(int j = 0;j <= as; j++) f[i][j] = -ap * j;
for(int j = 0;j <= P; j++) f[i][j] = std::max(f[i][j], f[i - 1][j]);
if(i <= w) continue;
l = 1, r = 0;
for(int j = P;j >= 0; j--) {
while(l <= r && p[l] > j + bs) l++;
// std::cout << l << std::endl;
while(l <= r && f[i - w - 1][p[r]] + p[r] * bp <= f[i - w - 1][j] + j * bp) r--;
p[++r] = j;
if(l <= r) f[i][j] = std::max(f[i][j], f[i - w - 1][p[l]] + p[l] * bp - j * bp);
}
l = 1, r = 0;
for(int j = 0;j <= P; j++) {
while(l <= r && p[l] < j - as) l++;
while(l <= r && f[i - w - 1][p[r]] + p[r] * ap <= f[i - w - 1][j] + j * ap) r--;
p[++r] = j;
if(l <= r) f[i][j] = std::max(f[i][j], f[i - w - 1][p[l]] + p[l] * ap - j * ap);
}
}
for(int i = 0;i <= P; i++) ans = std::max(ans, f[T][i]);
printf("%d", ans);
return 0;
}