单调队列/单调栈优化
介绍¶
例题CF372C Watching Fireworks is Fun
题目大意:城镇中有
初始你可在任意位置,你每个单位时间可以移动不大于
设
写出 状态转移方程:
这里的
我们尝试将状态转移方程进行变形:
由于
如果确定了
最后,式子变成了这个样子:
看到这一熟悉的形式,我们想到了什么?单调队列优化。由于最终式子中的
总的时间复杂度为
参考代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #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。设
时间复杂度
考虑优化
设
这样就转化为一个经典的单调队列优化形式了。
习题¶
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:Marcythm, hsfzLZH1, Ir1d, greyqz, Anguei, billchenchina, Chrogeek, ChungZH
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用