CodeForces 高分段 dp 选做
选取方式:CF *3000+ 按通过人数排序。
CF1188D Make Equal
记 \(cnt(x)\) 表示 \(x\) 二进制下 \(1\) 的个数,题目等价于求 \(x\) 使得
最小。
令 \(a_i = a_n - a_i\)。
从低位到高位考虑,假设当前要决策第 \(k\) 位,我们需要知道:
\(1.\) \(x\) 在这一位的值
\(2.\) \(a_i\) 在这一位的值
\(3.\) 之前的决策引起的进位
其中第三部分比较棘手,但是如果不考虑更高的位,那么 \(\mod 2^{k}\) 越大的 \(a\) 显然越容易进位,于是我们在每一位的决策是把所有 \(a\) 按 \(\mod 2^{k}\) 从大到小排序,那么进位的一定是一个前缀,直接枚举这个前缀,设 \(f_{i,j}\) 表示考虑前 \(i\) 位,第 \(i\) 位有 \(j\) 个进位的最小答案,简单讨论转移,时间复杂度 \(O(n \log n \log a)\)。
总结:
- 可以先设计一个暴力 dp 状态(实际上笔者在做题时先想到了按 \(\mod 2^k\) 分类,但是误以为是贪心,导致没有做出本题)
- 利用偏序关系化简状态,某些指数级的状态按顺序做就可能降为多项式级别
CF1476F Lanterns
假设我们求出了一个前缀灯集合的覆盖方式,如果仅仅记录是否能覆盖,那下一个灯向左可能导致之前的灯向右来获取更优的方案。
题目中要求最后每个位置都要被覆盖,于是可以这样设计状态:\(f_i\) 表示前 \(i\) 个灯能覆盖的最长前缀,分以下情况转移:
\(1.\) \(f_{i-1} < i: f_{i-1} \to f_i\)
\(2.\) 第 \(i\) 盏灯向右:\(\max{{f_{i-1},i+p_i}} \to f_i\)
\(3.\) 第 \(i\) 盏灯向左:找到最大的 \(t\) 使得 \(f_t > i - p_i\),\(\max{i-1,t+1+t_{p+1},...i - 1 + p_{i-1}} \to f_i\)
二分 \(t\),使用 st 表维护 \(\max i + p_i\),时间复杂度 \(O(n \log n)\)。
总结:
- 在复杂度不变的情况下增加信息,可以使得决策更易维护
- 最优子结构可以不连续
CF1647F Madoka and Laziness
一个初步的观察是一定有一个峰值是全局最大值,我们不妨设其位 \(x\),另一个峰值 \(y\),在它右边。
那么题目所求等价于:
\(1.\) 把 \(1 \to x\) 划分成两个递增子序列,最小化不含 \(x\) 的最右侧值。
\(2.\) 把 \(y \to n\) 划分成两个递减子序列,最小化不含 \(y\) 的最左侧值。
\(3.\) 把 \(x \to y\) 划分成一个递增,一个递减的子序列。
其中 \(1,2\) 可以简单 dp 解决,我们来讨论 \(3\),其实它就是 CF1144G。
容易设计一个朴素的 dp,将定义域值域互换,设 \(f_{i,0/1}\) 表示考虑到 \(i\),\(a_i\) 属于递增/递减序列时吗,另一个序列结尾的最小/最大值,讨论 \(a_i,a_{i - 1}, f_{i-1},f_i\) 的关系即可转移,时间复杂度 \(O(n)\)。
总结:
- 值域 / 定义域可以将较小的设计进状态。
CF713E Sonya Partymaker
二分答案,先考虑链的情况,容易发现这和 CF1476F 是相似的问题,然而在本题中所有段的长度相等,于是在第三类转移中只需要考虑之前两个位置的情况。
现在将环划分,可以发现把距离最大的两个相邻点分开就可以求得答案,时间复杂度 \(O(n \log n)\)。
总结:
- 环上问题的划分可以考虑最值或倒推。
- 在第三类转移中只需要考虑之前两个,实际上是用最小的状态蕴含了前面的情况(所有段的长度相等,结构相似)
CF1842H Tenzing and Random Real Numbers
直接对着随机变量做是困难的,我们转化为关心它们之间的大小关系。
然而这样还是很难处理限制,那么需要构造一个函数使得若 \(f(x) < f(y)\),则 \(x + y \leq 1\),这自然的引出了 \(0.5\) 作为中间变量。
具体的,如果我们知道了每个 \(x_i\) 在 \(0.5\) 的哪一侧,它们与 \(0.5\) 的距离顺序,就可以判断是否满足限制,我们枚举距离最近的前 \(i\) 个数的集合,新加入一个数的系数就只有 \(\frac{1}{2}\)(在 \(0.5\) 的哪一侧),与 \(\frac{1}{i + 1}\)(距离恰好为第 \(i\) 大),简单 dp 即可完成,时间复杂度 \(O(n 2^n)\)。
总结:
- 具体值难算可以只关心顺序
- 可以通过构造函数,中间变量来解决限制
CF933E A Preponderant Reunion
我们把操作放宽为任意减小。
令 \(f_{l,r}\) 为只考虑 \(l,r\) 使得 \(l\) 到 \(r \leq 0\) 的最小代价,设 \(c_l = p_l,c_{i} = \max{p_i - c_{i-1}, 0}\),那么
设 \(g_{l,r}\) 表示放宽后 \(l,r\) 的答案,有 \(f_{l,r} = g_{l - 1,l + 1}, f_{l,l+1} = g_{l-1,l + 2}\)。
在最优情况中 \(r - 1\) 保留了,即 \(g_{l-1,r + 1} = g_{l - 1, r - 1} + g_{r - 1, r + 1}\),于是极长的 \(0\) 段不超过 \(2\),这在原问题中同样成立。
设 \(dp_i\) 为保留 \(p_{i+1}\) (\(p_i \to 0\)) 使得前 \(i+1\) 个数合法的答案,则 \(dp_{i}\gets dp_{i-2}+p_i\) \(dp_i\gets dp_{i-3}+\max(p_i,p_{i-1})\),时间复杂度 \(O(n)\)。
CF1761F1 Anti-median (Easy Version)
通过观察 \(m = 1,2\) 可以发现,所有偶数位置都是局部极大值,奇数位置则是极小值(可能相反),且偶数位置呈峰状,奇数位置呈谷状。
偶数位的数和奇数位的数分开,把偶数位从后向前,奇数位接在偶数位后面从前向后地排在一个环上,形如 \(p_x,...,p_4,p_2,p_1,p_3,...,p_x\),任意最小得若干个数在环上连续,可以使用区间 dp 解决,注意对称的情况,时间复杂度 \(O(n^2)\)。
总结:
- 从简单情况入手,推广性质
- 最值结构在一定条件下可以转成连续段结构
CF1372E Omkar and Last Floor
首先有一个贪心的想法,尽量把 \(1\) 放在同一列。
直接做的话决策会互相影响,需要让每段之间相对独立,先来考虑合并 \(l_1,r_1,r_1 + 1,r_2\),只需要将 \(\in (l_1,r_2)\) 且跨过 \(r_1,r_1 +1\) 的区间的 \(1\) 全部放在一列。
这自然引出了区间 dp 的形式,设 \(f_{l,r}\) 表示只考虑包含于 \([l,r]\) 的区间的答案,枚举中间一列转移,时间复杂度 \(O(n^4)\)。
总结:
- 如果一个贪心的决策会互相影响,可以利用最优子结构写成 dp。
CF1530H Turing's Award
做时间倒流,我们需要 LIS 末尾的值,是否能把当前数加入 LIS 的左/右侧,以及 LCS 长度。
设 \(f_{i,j}\) 表示 LIS 长为 \(i\),末尾为 \(j\) 开头的最大值,\(g_{i,j}\) 表示 LIS 长为 \(i\),开头为 \(j\) 末尾的最小值,根据经典结论,随机排列的 LIS 是根号级别的,直接做这个 dp 即可,需要树状数组维护,时间复杂度 \(O(n \sqrt n \log n)\)。
总结:
- 覆盖类问题(只有最后一次有效)可以倒过来做。
- 定义域与值域互换。
CF1606 Tree Queries
考虑一个朴素的 \(dp\),设 \(f_{i,j}\) 为询问 \(i,j\) 的答案,\(f_{i,j} = \sum_{k \in son_i} \max(1, f_{k,j} - j)\)。
我们有 \(f_{u,x} \geq |son_u|\),实际上只有很少一部分情况是严格大于,其他情况是取等。
固定 \(x\),考虑取到大于号的最深的点 \(v\), 它有一个儿子 \(w\) 满足 \(∣son_w∣>k+1\),如果有多个,可以通过操作只保留一个,且 dp 值不减。
再考虑 \(v\) 的父亲 \(p\),这里 \(p\) 可能还有一些取到大于号的儿子,我们把除了 \(v\) 之外的子树中,取到大于号的点塞到 \(p\) 和 \(v\) 之间,取到等于号的点塞到 \(w\) 下面,这样 dp 值还是不见,最后树的结构是一个链接菊花图,容易说明取到大于的结点至多 \(\frac{n}{k}\) 个,对所有 \(k\) 求和是调和级数的,直接那个 \(dp\),只上传 \(>k\) 的 dp 状态,时间复杂度 \(O(n \log n)\)。
总结:
- 基于贪心/观察得到界,然后利用 dp 来做。
- 构造特殊结构。
CF1620F Bipartite Array
不是二分图等价于无奇环,在序列上比较特殊,等价于不存在长度为 \(3\) 的奇环,即最长下降子序列长度 \(\leq 2\)。
根据 Dilworth 引理,我们可以把序列划分成不超过 \(2\) 个上升子序列,那么这是一个比较常见的前缀 dp 模型。
设 \(f_{i,j},j = 0/1\) 表示第一个上升子序列到了 \(a_i\),是否取反,第二个上升子序列末尾最小是多少,简单讨论转移,记录前驱以输出方案,时间复杂度 \(O(n)\)。
总结:
- 如果一个判定条件不足以解决问题,考察是否有更严格的限制。
CF1149D Abandoning Roads
对于一棵最小生成树,每个轻边连通块内部都是一棵树,轻边连通块缩点后点之间的重边也是一棵树。也就是说,缩点后不存在重边组成的环(包括自环),路径一旦离开了一个轻边连通块就再也不会回来了。
于是考虑状压 dp,把轻边联通块的集合压入状态,做 Dij 算法,复杂度 \(O(2^n nm)\),无法通过。
考虑如果两次经过一个大小 \(\leq 3\) 的轻边联通块,那至少要走两条重边,不如在联通块内走,于是复杂度将为 \(O(2^\frac{n}{4} nm)\)。
总结:
- 只有两种元素,可以删去一种元素考虑。
- 处理局部的小结构可以简化复杂度,事实上也可以根据数据范围来猜想。
CF936D World of Tank
首先考虑没有切换行的情况,贪心地,能消除障碍就消除。
我们换一个视角,每秒积累 \(1\) 的火力,直到到达 \(T\)。
贪心保证了最优子结构,于是可以这样设计 dp,设 \(f_{i,j}\) 表示到了 \(i\) 行 \(j\) 列,最多能积累多少火力。
直接转移是 \(O(n)\) 的,实际上我们只会在障碍或其后一个切换行,时间复杂度降为 \(O(m)\)。
总结:
- 延后决策:如果当前能消除我们就直接假设他已经消除了,而不需要记录火力状态。(这个方法的适用范围:别急)
CF601E A Museum Robbery
线段树分治维护背包,使用标记永久化。

浙公网安备 33010602011771号