洛谷-P2569 股票交易
股票交易
\(dp\) + 单调队列优化
题目要求只能从第 \(w- i - 1\) 天买入或卖出
\(dp[i][j]\) 表示在第 \(i\) 天且当天持有 \(j\) 股的最大利润
有三种状态转移方式:
- 不买也不卖
\[dp[i][j] = dp[i-1][j]
\]
- 从第 \(w - 1 - i\) 天买入
\[dp[i][j] = \max_{k=j-AS_i}^{j-1}(dp[w - 1 - i][k] - AP_i * (j-k))
\]
将常数提出来之后可以考虑用单调队列优化
\[dp[i][j] = \max_{k=j-AS_i}^{j-1}(dp[w - 1 - i][k] + k * AP_i) - j * AP_i
\]
- 从第 \(w - 1 - i\) 天卖出
\[dp[i][j] = \max_{k=j+1}^{j+BS_i}(dp[w - 1 - i][k] + BP_i * (k - j))
\]
同理,提取常数后用单调队列优化
\[dp[i][j] = \max_{k=j+1}^{j+BS_i}(dp[w - 1 - i][k] + k * BP_i) - j * BP_i
\]
#include <iostream>
#include <iostream>
#include <cstdio>
#include <deque>
#include <algorithm>
using namespace std;
typedef long long ll;
#define pii pair<ll, ll>
const int maxn = 2010;
const ll inf = 0x3fffffffffffffff;
ll dp[maxn][maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t, p, w;
cin >> t >> p >> w;
for(int i=0; i<=t; i++) for(int j=0; j<=p; j++) dp[i][j] = -inf;
dp[0][0] = 0;
for(int i=1; i<=t; i++)
{
ll ap, bp, as, bs;
cin >> ap >> bp >> as >> bs;
int pre = max(0, i - w - 1);
deque<pii>q;
for(int j=p; j>=0; j--)
{
while(q.size() && q.back().first <= dp[pre][j] + j * bp)
q.pop_back();
q.push_back({dp[pre][j] + j * bp, j});
while(q.front().second > j + bs) q.pop_front();
dp[i][j] = max(dp[i-1][j], q.front().first - j * bp);
}
while(q.size()) q.pop_front();
for(int j=0; j<=p; j++)
{
while(q.size() && q.back().first <= dp[pre][j] + j * ap)
q.pop_back();
q.push_back({dp[pre][j] + j * ap, j});
while(q.front().second < j - as) q.pop_front();
dp[i][j] = max(dp[i][j], q.front().first - j * ap);
}
}
ll ans = -inf;
for(int j=0; j<=p; j++)
ans = max(ans, dp[t][j]);
cout << ans << endl;
return 0;
}