感觉我dp的状态定义和其他的人都不一样。
dp[j][k]表示拥有j股还要等待k天的最大值,这样是可以把第i天这一维给省略掉的。(这样做的话要给间隔w++,转换成等待的时间)
状态转移:
每一天开始,都要把所有等待时间给减一天,f[j][k] = f[j][k+1]
接着就是卖出和买入
卖出:$f[j][w] = max(f[t][0] + (t - j) * b[i]) ,其中 j < t <= min(Maxp, j + d[i])$
买入:$f[j][w] = max(f[t][0] + (j - t) * a[i]) ,其中(max(0, j - c[i]) <= t < j)$
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 2010;
int n, m, p, a[N], b[N], c[N], d[N], f[N][N], z[N];
int main() {
scanf("%d%d%d", &n, &m, &p); // m = number, p = day
for (int i = 1; i <= n; i++)
scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
memset(f, 0xcf, sizeof(f)); f[0][0] = 0;
int inf = f[0][1], ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
f[j][0] = max(f[j][0], f[j][1]);
for (int k = 1; k < p; k++) f[j][k] = f[j][k + 1];
if (p >= 1) f[j][p] = inf;
}
for (int j = 0; j <= m; j++) z[j] = f[j][0];
//buy
for (int j = 1; j <= m; j++)
for (int k = 1; k <= min(c[i], j); k++)
f[j][p] = max(f[j][p], z[j - k] - k * a[i]),
ans = max(ans, f[j][p]);
//sell
for (int j = 0; j < m; j++)
for (int k = 1; j + k <= m && k <= d[i]; k++)
f[j][p] = max(f[j][p], z[j + k] + k * b[i]),
ans = max(ans, f[j][p]);
}
cout << ans << endl;
return 0;
}
但是这样子维护是$O(N^3)$的,所以我们要优化状态转移
1.
$f[j][k] = f[j][k+1]$
我们发现只是让f往左边平移了一个,总体的顺序是不变的,所以我们只要将一个时间戳++
2.
$
f[t][0] + (t - j) * b[i] = f[t][0] + t * b[i] - j * b[i]
$
$
(f[t][0] + t * b[i])就可以用单调队列维护了
$
时间变成$O(N^3)$
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 2010;
int n, m, p, a[N], b[N], c[N], d[N], f[N][N], z[N];
int l, r, q[N];
int main() {
scanf("%d%d%d", &n, &m, &p); p++;
for (int i = 1; i <= n; i++)
scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
memset(f, 128, sizeof(f)); f[0][0] = 0;
int inf = f[0][1], ans = 0, time = 0;
for (int i = 1; i <= n; i++) {
int jn = time;
time++; if (time == p + 1) time = 0;
for (int j = 0; j <= m; j++) {
f[j][time] = max(f[j][time], f[j][jn]);
if (p >= 1) f[j][jn] = inf;
}
for (int j = 0; j <= m; j++) z[j] = f[j][time];
//buy
l = r = 1, q[1] = 0;
for (int j = 1; j <= m; j++) {
while (l <= r && q[l] < max(j - c[i], 0)) l++;
f[j][jn] = max(f[j][jn], z[q[l]] - (j - q[l]) * a[i]);
ans = max(ans, f[j][jn]);
while (l <= r && z[q[r]] + q[r] * a[i] <= z[j] + j * a[i]) r--;
q[++r] = j;
}
//sell
l = r = 1, q[1] = m;
for (int j = m - 1; j >= 0; j--) {
while (l <= r && q[l] > min(m, j + d[i])) l++;
f[j][jn] = max(f[j][jn], z[q[l]] + (q[l] - j) * b[i]);
ans = max(ans, f[j][jn]);
while (l <= r && z[q[r]] + q[r] * b[i] <= z[j] + j * b[i]) r--;
q[++r] = j;
}
}
cout << ans << endl;
return 0;
}
时间变成O(N3)
O(N2)吧
tql