Monotonous Queue/Stack
介绍¶
例题CF372C Watching Fireworks is Fun
题目大意:城镇中有
初始你可在任意位置,你每个单位时间可以移动不大于
设
写出 状态转移方程:
这里的
我们尝试将状态转移方程进行变形:
由于
如果确定了
最后,式子变成了这个样子:
看到这一熟悉的形式,我们想到了什么?单调队列优化。由于最终式子中的
总的时间复杂度为
参考代码
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 150000 + 10;
const int maxm = 300 + 10;
ll f[2][maxn];
ll a[maxm], b[maxm], t[maxm];
int n, m, d;
int que[maxn];
int fl = 1;
void init() {
memset(f, 207, sizeof(f));
memset(que, 0, sizeof(que));
for (int i = 1; i <= n; i++) f[0][i] = 0;
fl = 1;
}
void dp() {
init();
for (int i = 1; i <= m; i++) {
int l = 1, r = 0, k = 1;
for (int j = 1; j <= n; j++) {
for (; k <= min(1ll * n, j + d * (t[i] - t[i - 1])); k++) {
while (l <= r && f[fl ^ 1][que[r]] <= f[fl ^ 1][k]) r--;
que[++r] = k;
}
while (l <= r && que[l] < max(1ll, j - d * (t[i] - t[i - 1]))) l++;
f[fl][j] = f[fl ^ 1][que[l]] - abs(a[i] - j) + b[i];
}
fl ^= 1;
}
}
int main() {
cin >> n >> m >> d;
for (int i = 1; i <= m; i++) cin >> a[i] >> b[i] >> t[i];
// then dp
dp();
ll ans = -1e18;
for (int i = 1; i <= n; i++) ans = max(ans, f[fl ^ 1][i]);
cout << ans << endl;
return 0;
}
讲完了,让我们归纳一下单调队列优化动态规划问题的基本形态:当前状态的所有值可以从上一个状态的某个连续的段的值得到,要对这个连续的段进行 RMQ 操作,相邻状态的段的左右区间满足非降的关系。
单调队列优化多重背包¶
问题描述
你有
不了解背包 DP 的请先阅读 背包 DP。设
时间复杂度
考虑优化
设
这样就转化为一个经典的单调队列优化形式了。
习题¶
buildLast update and/or translate time of this article,Check the history
editFound smelly bugs? Translation outdated? Wanna contribute with us? Edit this Page on Github
peopleContributor of this article Marcythm, hsfzLZH1, Ir1d, greyqz, Anguei, billchenchina, Chrogeek, ChungZH
translateTranslator of this article Visit the original article!
copyrightThe article is available under CC BY-SA 4.0 & SATA ; additional terms may apply.