20240918:DP选做
本文为 @A_zjzj《dp 专题》学习笔记。
转移性质
Lanterns
题意:\(n\) 个灯笼拍成一排,第 \(i\) 个灯笼具有 \(p_i\) 的亮度。每个灯笼要么朝向左照亮 \([i - p_i, i - 1]\),要么朝向右照亮 \([i + 1, i + p_i]\)。
寻找一种方案,为所有的灯笼定向,使得每一个灯笼被至少一个其他灯笼照亮。\(2 \le n \le 3\times 10^5, p_i \in [0, n]\)。
设 \(f_i\) 表示前 \(i\) 盏灯能覆盖的最长前缀,考虑几种转移:
- 前 \(i - 1\) 盏灯能覆盖 \(i\),\(f_i \gets \max(f_{i - 1}, i + p_i)\)。
- 前 \(i - 1\) 盏灯不能覆盖 \(i\),先把 \(i\) 忽略,之后再定向,\(f_i \gets f_{i - 1}\)。
- \(i\) 向左覆盖,存在一个 \(f_j + 1 \ge i - p_i\),所有 \((j, i)\) 的灯向右定向,\(f_i \gets \max(i - 1,\ j + 1 + p_{j + 1}, \cdots, i - 1 + p_{i - 1})\)。
显然有 \(f_{i - 1} \le f_i\),二分 \(j\),树状数组维护后缀最大值。submission
来源不明的一道题
题意:给出 \(n\) 和 \(a_{2 \sim n}, b_{2 \sim n}\),表示 \(i\) 有单向边连向 \([a_i, i - 1]\),\([b_i, i - 1]\) 有单向边连向 \(i\),边权为 \(1\)。
设 \(d(i, j)\) 表示 \(i\) 到 \(j\) 的最短路,求 \(\bigoplus_{i, j} d(i,j) \times (i + j)\)。\(1\le n\le 6000,\ a_i < i,\ b_i < i,\ \text{1s}\)。
如果从 \(i\) 向左走一步到 \(j\),紧跟着向右走到 \(k\),这是一定不优的:
- \(k \le i\),显然有 \(a_i \le j < k \le i\),可以一步或零步走到。
- \(k > i\),\(j\) 能一步到 \(k\),说明 \(b_k \le j\),说明 \(i\) 也能一步到 \(k\)。
因此最优方案一定是先向右走若干步,再向左走若干步。
枚举起点 \(s\),设 \(f_i\) 表示 \(s\) 到 \(i\) 的最短路,分两部分转移(从前往后扫一遍,再从后往前扫一遍):
第一部分:\(f_i \gets f_j + 1,\ b_i \le j < i\);第二部分:\(f_i \gets f_j + 1,\ a_j \le i < j\)。可以线段树做到平方对数。
以向右的转移为例,如果 \(i < j\land f_i \ge f_j\),\(f_i\) 显然不优。
设 \(g_x = \max_\limits{j < i\land f_j = x} j\),表示值为 \(x\) 时的最优决策点,显然 \(f_i\) 的上界为 \(x = f_{i - 1} + 1\)。不断使 \(x \to x - 1\),直到 \(g_{x - 1} < b_i\)。
用 \(x\) 更新 \(f_i\),并使 \(g_x = i\)。上述做法依赖于 \(g_0\sim g_{f_{i - 1}}\) 是单调递减的,可以归纳证明。势能增量 \(O(n)\),复杂度 \(O(n)\)。
对于向左的转移,如果 \(a_i \le a_j \land f_i \le f_j\),\(f_j\) 显然不优。设 \(g_x = \min\limits_{j > i \land f_j = x} a_j\)。
\(f_i\) 的上界是 \(\min(f_i, f_{i + 1} + 1)\),不断使 \(x \to x - 1\),直到 \(g_{x - 1} > i\),归纳证明 \(g_0 \sim g_{f_{i + 1}}\) 是单调递增的。
时间复杂度 \(O(n^2)\)。submission
一类特殊题型
求一个排列 \(\{p\}\),最小(大)化如下值:
其中 \(f(i, j)\) 如下:
考虑按照 \(p_i\) 的大小,从小到大插入序列的过程,维护若干连续段(只是说明某些元素在最终排列上连续,并没有确定位置)。
每次插入有以下情况:
- 将两个连续段合并成一个。
- 插入一个连续段的左边/右边。
- 新增一个连续段。
由于保证了插入顺序,容易算出每个元素的贡献。另外,需要维护连续段个数,保证最终连续段合并成一个。
可能需要判断插入时是否插在全局的开头或末尾。
Ant Man
题意:给定排列 \(\{p\}\) 的第一个元素 \(s\) 和最后一个元素 \(e\),找出一个排列,最小化:
其中,\(2\le n \le 5000,\ x_1 < x_{2} < \cdots < x_n\)。
和原模型基本一致,\(f(i, j)\) 表示插入前 \(i\) 个数,分成 \(j\) 个连续段的最小代价。
注意 \(s, e\) 没有合并连续段的转移,\(s\) 只算右边贡献,\(e\) 只算左边贡献,\(s\) 所在连通块不能右插,\(e\) 不能左插。
新增一个 \(i\) 作为连通块时,需要满足 \(j - [i > s] - [i > e] \ge 1\),否则无法新增。submission
[JOI Open 2016] 摩天大楼
题意:互不相同的 \(n\) 个整数 \(A_1,A_2,⋯ ,A_n\) 按一定顺序排成 \(f_1,f_2,⋯ ,f_n\)。
求满足 \(\vert f_1−f_2\vert+⋯+\vert f_{n−1}−f_n\vert≤L\) 的方案数。\(1 \le n \le 100, 1 \le A_i, L \le 1000\)。
不能和上题一样拆贡献,因为最后答案在操作过程中可增可减,有可能当前大于 \(L\),最后又合法,状态上界不能估计。
记从小到大排序后的数组为 \(\{a\}\),我们最后的贡献一定是若干 \(a_j - a_i,\ j > i\) 相加的形式。
考虑微元贡献法,\(a_j - a_i = \sum\limits_{k = i}^{j - 1} a_{k + 1} - a_k\),换而言之 \(a_{k + 1} - a_k\) 会贡献到所有 \(i \le k < j\) 的贡献上。
假设当前插入 \(a_{k + 1}\),此时所有连续段的端点都满足 \(\le k\),而端点会在未来与 \(> k\) 的元素相连。因此 \(a_{k + 1} - a_k\) 的贡献次数就是当前端点个数。
这样就避免了答案的负增长,但还不是很完备。如果第一个元素已经被钦定,那么其所在连续段左端点不会产生贡献;同理最后一个元素。
设 \(f(i, j, k, d)\) 表示插入前 \(i\) 个数,产生 \(j\) 个连续段,当前答案为 \(k\),且有 \(d \le 2\) 个边界(首尾)已经确定的方案数。
转移时,有 \(k^\prime \gets k + (a_{i + 1} - a_i) \times (2j - d)\):
- 新增一个连续段,不作为边界:\(f(i + 1, j + 1, k^\prime , d) \gets (j + 1 - d) \times f(i, j, k, d)\)。
- 新增一个连续段,作为边界:\(f(i + 1, j + 1, k^\prime , d + 1) \gets (2 - d) \times f(i, j, k, d)\)。
- 连接两个连续段:\(f(i + 1, j - 1, k^\prime, d) \gets (j - 1) \times f(i, j, k, d)\)。
- 靠到一个连续段左/右边,不作为边界:\(f(i + 1, j, k^\prime, d) \gets (2j - d)\times f(i, j, k, d)\)。
- 靠到一个连续段左/右边,作为边界:\(f(i + 1, j, k^\prime, d) \gets (2 - d)\times f(i, j, k, d)\)。
时间复杂度 \(O(n^2L)\)。submission
DP构建
Price Combo
题意:

浙公网安备 33010602011771号