[SCOI2010]股票交易
题面传送
这题好想,dp嘛。但是转移容易漏。
令\(dp[i][j]\)表示第\(i\)天,手里有\(j\)股时的最大利润,那么
1.啥也不干:\(dp[i][j] = dp[i - 1][j]\).
2.凭空买(前几天啥也不干):\(dp[i][j] = max \{dp[i][j], -j * ap[i]\}\).(我就漏了这个)
3.在第\(i\)天买\(j-k\)股:\(dp[i][j] = max \{dp[i - w - 1][k] - (j - k) * ap[i] \}(0 \leqslant j-k \leqslant as[i])\).
4.同理,在第\(i\)天卖\(j - k\)股:\(dp[i][j] = max \{dp[i - w - 1][k] + (j - k) * bp[i]\}(0 \leqslant j - k \leqslant bs[i])\).
对于“买”这个式子(卖同理),稍微变形一下:\(dp[i][j] = max \{dp[i - w - 1][k] + k * ap[i] \} - j * ap[i]\),就变成了滑动窗口问题了,单调队列可以解决。
做法就是对于每一层,正着和倒着跑一遍单调队列,分别处理买和卖两个转移。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const ll INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 2e3 + 5;
In ll read()
{
ll ans = 0;
char ch = getchar(), las = ' ';
while(!isdigit(ch)) las = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(las == '-') ans = -ans;
return ans;
}
In void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, m, w;
int ap[maxn], bp[maxn], as[maxn], bs[maxn];
int dp[maxn][maxn];
deque<int> q;
In void work1()
{
for(int i = 1; i <= n; ++i)
{
for(int j = 0; j <= m; ++j)
{
dp[i][j] = dp[i - 1][j];
if(j <= as[i]) dp[i][j] = max(dp[i][j], -j * ap[i]);
}
if(i <= w) continue;
q.clear();
for(int j = 0; j <= m; ++j)
{
int* D = dp[i - w - 1];
while(!q.empty() && D[q.back()] + q.back() * ap[i] <= D[j] + j * ap[i]) q.pop_back();
while(!q.empty() && q.front() < j - as[i]) q.pop_front();
q.push_back(j);
dp[i][j] = max(dp[i][j], D[q.front()] - (j - q.front()) * ap[i]);
}
q.clear();
for(int j = m; j >= 0; --j)
{
int* D = dp[i - w - 1];
while(!q.empty() && D[q.back()] + q.back() * bp[i] <= D[j] + j * bp[i]) q.pop_back();
while(!q.empty() && q.front() - j > bs[i]) q.pop_front();
q.push_back(j);
dp[i][j] = max(dp[i][j], D[q.front()] + (q.front() - j) * bp[i]);
}
}
int ans = -INF;
for(int i = 0; i <= m; ++i) ans = max(ans, dp[n][i]);
write(ans), enter;
}
int main()
{
n = read(), m = read(), w = read();
for(int i = 1; i <= n; ++i)
ap[i] = read(), bp[i] = read(), as[i] = read(), bs[i] = read();
Mem(dp, 128), dp[0][0] = 0;
work1();
return 0;
}