洛谷P2569 [SCOI2010] 股票交易 题解
题意:
最近 \(\text{lxhgww}\) 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,\(\text{lxhgww}\) 预测到了未来 \(T\) 天内某只股票的走势,第 \(i\) 天的股票买入价为每股 \(AP_i\),第 \(i\) 天的股票卖出价为每股 \(BP_i\)(数据保证对于每个 \(i\),都有 \(AP_i \geq BP_i\)),但是每天不能无限制地交易,于是股票交易所规定第 \(i\) 天的一次买入至多只能购买 \(AS_i\) 股,一次卖出至多只能卖出 \(BS_i\) 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 \(W\) 天,也就是说如果在第 \(i\) 天发生了交易,那么从第 \(i+1\) 天到第 \(i+W\) 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 \(\text{MaxP}\)。
在第 \(1\) 天之前,\(\text{lxhgww}\) 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,\(T\) 天以后,\(\text{lxhgww}\) 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入格式:
输入数据第一行包括 \(3\) 个整数,分别是 \(T\),\(\text{MaxP}\),\(W\)。
接下来 \(T\) 行,第 \(i\) 行代表第 \(i-1\) 天的股票走势,每行 \(4\) 个整数,分别表示 \(AP_i,\ BP_i,\ AS_i,\ BS_i\)。
输出格式:
输出数据为一行,包括 \(1\) 个数字,表示 \(\text{lxhgww}\) 能赚到的最多的钱数。
数据范围:
\(0\leq W<T\leq 2000,1\leq\text{MaxP}\leq 2000,1\leq BP_i\leq AP_i\leq 1000,1\leq AS_i,BS_i\leq\text{MaxP}\)。
设 \(f(i,j)\) 为前 \(i\) 天,手上有 \(j\) 股股票的最大收益。
初值是 \(f(i,j)=-\infty\) 。考虑转移。
\(i\) 是第一次买,有 \[ f(i,j) = -j\times \mathrm{ap}_i \]
不买也不卖,有 \[ f(i,j) \uparrow f(i-1,j) \]
买,从 \(f(i-w-1,\,k)\) 转移一定不劣,那么 \[ f(i,j) \uparrow \max_{j - \mathrm{as}_i \le k \le j}\{f(i-w-1,\,k) - (j - k)\times \mathrm{ap}_i\} \]
卖,同理,有 \[ f(i,j) \uparrow \max_{j \le k \le j + \mathrm{bs}_i}\{f(i-w-1,\,k) + (k - j)\times \mathrm{bp}_i\} \]
显然可以单调队列优化。
时间复杂度 \(\mathcal{O}(n)\)
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x, int y) { x < y ? x = y : 0; }
void down(int &x, int y) { x > y ? x = y : 0; }
#define rep(i, a, b) for(int i = (a), i##END = (b); i <= i##END; i++)
#define Rep(i, a, b) for(int i = (a), i##END = (b); i >= i##END; i--)
#define N ((int)(2e3 + 15))
int st, en, q[N], f[N][N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int n, m, w; cin >> n >> m >> w;
memset(f, 0xc0, sizeof(f));
rep(i, 1, n)
{
static int ap, bp, as, bs; cin >> ap >> bp >> as >> bs;
rep(j, 0, as) f[i][j] = -1 * j * ap;
rep(j, 0, m) up(f[i][j], f[i - 1][j]);
if(i <= w) continue; st = en = 0;
rep(j, 0, m)
{
while(st < en && q[st + 1] < j - as) ++st;
while(st < en && f[i - w - 1][q[en]] + q[en] * ap <= f[i - w - 1][j] + j * ap) --en;
q[++en] = j;
if(st < en) up(f[i][j], f[i - w - 1][q[st + 1]] + q[st + 1] * ap - j * ap);
}
st = en = 0;
Rep(j, m, 0)
{
while(st < en && q[st + 1] > j + bs) ++st;
while(st < en && f[i - w - 1][q[en]] + q[en] * bp <= f[i - w - 1][j] + j * bp) --en;
q[++en] = j;
if(st < en) up(f[i][j], f[i - w - 1][q[st + 1]] + q[st + 1] * bp - j * bp);
}
}
int res = 0; rep(i, 0, m) up(res, f[n][i]);
cout << res << '\n';
return 0;
}
参考文献: