杂题选做Ⅰ
本博客将会收录一些贪心/构造的我认为较有价值的题目,这样可以有效的避免日后碰到 P7115 或者 P7915 这样的题就束手无策进而垫底的情况/dk
某些题目虽然跟贪心关系不大,但是在 CF 上有个 greedy 的 tag,这种题目大概率也会被我收录进来(比方说这篇博客里大概率会收录不少 DP 题,因为 CF 上不少 DP 题都莫名其妙地打上了一个 greedy 的 tag
upd on 2021.11.30:由于更到后面发现后面的题目和贪心、DP 之类的关系不算太大了,倒是混入了不少计数题,故改名“杂题选做”,但是为了避免连接出锅还是保留原来的 url。
1. CF1592F1 Alice and Recoloring 1
首先很明显我们不会选择翻转包含 \((1,m),(n,1)\) 的矩形,因为它们完全可以等效于翻转两次包含 \((1,1)\) 的矩形,而前者代价不小于 \(2\),后者代价为 \(2\),因此我们只用考虑包含 \((n,m)\) 的矩形即可。
我们考虑记 \(a_{x,y}\) 表示 \((x,y)\) 格子颜色是否为黑色,再记 \(b_{x,y}=a_{x,y}\oplus a_{x,y+1}\oplus a_{x+1,y}\oplus a_{x+1,y+1}\),那么可以发现 \(1\) 操作等价于单点翻转 \((x,y)\) 的 \(b\) 值,而 \(4\) 操作等价于翻转 \((x-1,y-1),(x-1,m),(n,y-1),(n,m)\) 四个点的 \(b\) 值,注意到一个性质就是我们 \(4\) 操作使用的次数肯定不会超过 \(1\),因为两次操作 \(4\) 可以用六次操作 \(1\) 代替,而二者代价都是 \(6\),因此我们完全可以将两次 \(4\) 操作变为 \(6\) 次 \(1\) 操作且答案不会变得更劣。
这样问题就简单了,我们统计一下有多少个 \(b_{x,y}=1\),再统计一下是否存在一组 \((x,y)\),满足 \(b_{x-1,y-1},b_{x-1,m},b_{n,y-1},b_{n,m}\) 均为 \(1\),如果存在则可以将这四次 \(1\) 操作变为一次 \(4\) 操作,答案减少 \(1\)。
时间复杂度 \(\mathcal O(nm)\)。
2. CF1592F1 Alice and Recoloring 2
和上一题一样,我们同样不会翻转包含 \((1,m),(n,1)\) 的矩形,结论同上。
与上一题不同的是,由于此题翻转 \((n,m)\) 的代价为 \(2\),因此“翻转包含 \((n,m)\) 的矩形的次数不超过 \(1\)“这一结论就不再成立了,我们不妨来挖掘一下其他性质。我们记集合 \(S\) 表示 \(4\) 操作作用过的点,那么可以发现以下性质:
Observation 1. \(\forall (x,y),(x’,y’)\in S\),都有 \(x\ne x’,y\ne y’\)
因为如果我们翻转两个在同一行的元素,我们完全可以用 \(4\) 次 \(1\) 操作代替两次 \(2\) 操作。而二者拥有相同的花费。
Observation 2. \(\forall (x,y)\in S\),都有 \(b_{x-1,y-1}=b_{x-1,m}=b_{n,y-1}=1\)
否则翻转完这个含 \((x,y)\) 的矩形后,肯定会有至少一个 \(0\) 变成了 \(1\),此时我们肯定要再花至少 \(1\) 的代价把这个 \(1\) 变回 \(0\),而这样一来就已经有 \(3\) 的代价了,肯定不比直接翻 \(3\) 个点更优。
这样一来模型就很明显了,我们希望尽可能多地使用 \(4\) 操作,而使用 \(4\) 操作需要满足 \(b_{x-1,y-1}=b_{x-1,m}=b_{n,y-1}=1\) 且 \(x-1,y-1\) 互不重复,这样能比不用 \(4\) 操作节省 \(1\) 的代价,这不禁令我们往二分图匹配的方向去思考。具体来说我们建立两排点,如果 \((x,y)\) 满足 \(b_{x-1,y-1}=b_{x-1,m}=b_{n,y-1}=1\),那么我们就从左部的 \(x\) 点向右部的 \(y\) 点连一条边,然后跑二分图最大匹配即可知道我们最多可以使用多少次 \(4\) 操作,这样通过网格上 \(1\) 的个数,减去二分图最大匹配的大小即可得到答案。注意到每次使用 \(4\) 操作都会改变一次 \(b_{n,m}\),因此如果二分图最大匹配是奇数,我们在统计网格上 \(1\) 的个数时,要反转 \(1\) 的状态。
3. CF1521D Nastia Plays with a Tree
彻底废柴了/dk,连 2500 的贪心题都做不出来了
首先我们想到一个非常假的贪心:我们从上至下对树进行一遍 DFS,然后每次尝试将每个点的子树变成一条链,如果发现儿子个数 \(\ge 2\) 就将那些分叉摘下来贴到一个儿子处。
该做法一脸过不去的样子,离谱到连样例都过不去,其原因在于它忽略了一种情况:那就是如果一个点的子树有两个分叉,并且两个分叉都是一条垂下去的链,那么如果抛开这个点与其父亲的边,那么这个点的子树也是一条链,因此合并时需要分情况讨论。我们将“去掉一个点与其父亲的连边后,子树是一条链”的子树,分为“一条垂下去链”和“由两条垂下去的链组合而成的链”两种情况讨论:
- 如果这个点的子树中,有至少两条“一条垂下去链”,那么我们会选择保留这两条垂下去的链,合并成一条“由两条垂下去的链组合而成的链”,然后其他链都接到这条链上。
- 如果这个点的子树中,恰有一条“一条垂下去链”,那么我们直接将其他链都接到这条链上形成一条更大的“一条垂下去链”即可。
- 如果这个点的子树中,没有“一条垂下去链”,那么我们随便选择一条“由两条垂下去的链组合而成的链”,然后将其余链都接到这条链上即可。
时间复杂度 \(\mathcal O(n)\)。
4. CF1455F String and Operations
考虑 DP。注意到进行完前 \(i\) 次操作之后,\(s_{i+1}\) 要么在 \(i\),要么在 \(i+1\),取决于上一次 \(s_i\) 是否在 \(i\) 位置且上一次执行的是否是 R 操作。因此设 \(dp_{i,0/1}\) 表示进行完前 \(i\) 次操作后,\(s_{i+1}\) 否/是被移到了 \(i\) 位置后最小的字典序,转移就分 OUDLR 五种情况转移即可,时间复杂度 \(\Theta(n^2)\)。
针对上述平方的 dp 我们其实还有进一步优化的空间。注意到每次操作我们只会影响 \([i-2,i+1]\) 这段区间内位置上的值,因此我们字符串只用存 \(4\) 位,每次 DP 过程中确定出 \(s_{i-3}\) 的最小值,然后从 \(s_{i-3}\) 达到最小值的位置转移即可。这样复杂度可优化到线性。
5. CF1474E What Is It?
一开始结论猜错了,以为是 \(\sum\limits_{i=1}^{n-1}i^2\),后来对着错误的数据手玩之后才得到正确的结论/cg
结论:最大权值为 \((n-1)^2+(n-2)^2+(n-2)^2+(n-3)^2+(n-3)^2+(n-4)^2+(n-4)^2+\cdots\),如此加 \(n-1\) 个数得到的和。
构造:构造一个大小为 \(n\) 的置换环,上面的元素分别是 \(1\to n-1\to n-2\to n-3\to\cdots\to\lfloor\dfrac{n}{2}\rfloor+1\to n\to 2\to 3\to\cdots\lfloor\dfrac{n}{2}\rfloor\to 1\),然后操作 \(\lfloor\dfrac{n-1}{2}\rfloor\) 次 \(1\)(即交换 \(1\) 与 \(p_1\)),再操作 \(n-1-\lfloor\dfrac{n-1}{2}\rfloor\) 次 \(n\) 即可。手玩一下即可发现这样构造可以达到上面的上界。
证明:下面来证明下 \((n-1)^2+(n-2)^2+(n-2)^2+(n-3)^2+(n-3)^2+(n-4)^2+(n-4)^2+\cdots\) 是最大代价的上界。首先 \((n-1)^2\) 最多被贡献一次,证明显然,对于 \((n-2)^2\),显然只可能 \((1,n-1),(2,n)\) 操作时会产生,因此最多产生 \(2\) 次贡献,而对于 \(i\le n-3\),我们考虑归纳证明。显然 \(i^2\) 的贡献只可能在 \(1,2,3,\cdots,n-i,i+1,i+2,\cdots,n\) 这 \(2(n-i)\) 个数之间操作得到,而要想前面达到 \((n-1)^2+2(n-2)^2+\cdots+2(n-i+1)^2\) 的上界,前面必须进行 \(2(n-i)-3\) 次操作,而合并 \(2(n-i)\) 个数至多可以进行 \(2(n-i)-1\),也就是说如果我们希望前面 \(2(n-i)-3\) 次操作的总收益尽可能大,\(i^2\) 只能贡献两次,如此归纳下去即可知道结论成立。
时间复杂度 \(\mathcal O(n)\)。
6. CF1543E The Final Pursuit
一开始又猜错结论了,以为 \(n\ge 3\) 第二问答案肯定是 \(-1\),又是根据错误的数据猜结论的一天(
首先第一问很容易,由于数据保证合法,因此可以随便钦定一个点为 \(0\),并以任意顺序钦定它们为 \(2^0,2^1,2^2,\cdots,2^{n-1}\)。然后 BFS 一遍即可,每次 BFS 时取出一个点 \(x\) 并将其所有邻居的编号设为该点编号与该邻居编号的 or。
难点在于第二问,手动构造 \(n=4\) 时我们有这样一个感觉,就是 \(n\) 如果可以表示成 \(2^k\) 的形式,那么第二问答案就不是 \(-1\)。否则第二问答案就是 \(-1\)。碰到这样形式的题我们可以很自然地想到归纳构造,具体来说 \(n=1\) 的构造是很 trivial 的,而假设 \(res_k\) 为当 \(n=2^m\) 时,点 \(k\) 的颜色,那么考虑根据 \(res_k\) 构造出 \(res’_k\) 表示当 \(n=2^{m+1}\) 时,点 \(k\) 的颜色。稍加思考可以得到:
为什么这样归纳构造出来的颜色序列符合要求?首先对于我们称所有 \(\lfloor\dfrac{k}{2^m}\rfloor\) 相同的 \(k\) 为“同一块”,那么每个点的所有邻居中,恰好有 \(2^m\) 个与其在同一块,另外 \(2^m\) 个与其不在同一块中,显然与其在同一块的点,它们的 \(2^{m}·(\text{popcount}(\lfloor\frac{k}{2^m}\rfloor)\bmod 2)\) 与 \(res_{\lfloor\frac{k}{2^m}\rfloor}\) 都是相同的,根据 \(n=2^m\) 的构造可知所有邻居的 \(res_{k\bmod 2^m}\) 都是不同的,因此与其在同一块中的邻居的颜色不会重复,而对于不在同一块之间的邻居,由于它的邻居与其异或起来一定是 \(2\) 的幂,且由于这些邻居与其不在同一块中,因此对于所有符合该要求的邻居 \(k’\),都有 \(\text{popcount}(\lfloor\frac{k’}{2^m}\rfloor)\bmod 2\ne \text{popcount}(\lfloor\frac{k}{2^m}\rfloor)\),且 \(k’\equiv k\pmod{2^m}\),因此所有这样的邻居的 \(2^{m}·(\text{popcount}(\lfloor\frac{k}{2^m}\rfloor)\bmod 2)\) 与 \(res_{k\bmod 2^m}\) 都是相同的,唯一不同的肯定是 \(res_{\lfloor\frac{k}{2^m}\rfloor}\),而如果我们把每一块缩成一个点,那得到的肯定是一个 \(n=2^m\) 的图,因此这些邻居的 \(res_{\lfloor\frac{k}{2^m}\rfloor}\) 也互不相同。又因为对于与 \(k\) 在同一块与与 \(k\) 不在同一块的邻居,它们之间的 \(\lfloor\dfrac{k}{2^m}\rfloor\) 的奇偶性必定完全不同,因此它们必然一类全部 \(<2^m\),一类全部 \(\ge 2^m\),不存在重复的情况。
7. CF1375E Inversion SwapSort
一道挺常规的题。
考虑归纳构造,每次将最大的元素还原到最右边的位置处,而我们又不能改变剩余元素的相对位置关系,因此考虑将所有大于原来最后一个元素的数拎出来并按照它们的大小排成一列,假设为 \(a_{i_1},a_{i_2},\cdots,a_{i_k}\),那么我们的目标是 \(a_n\) 移到 \(a_{i_1}\) 的位置,\(a_{i_1}\) 移到 \(a_{i_2}\) 的位置,……,\(a_{i_{k-1}}\) 移到 \(a_{i_k}\) 的位置,\(a_{i_k}\) 移到 \(a_n\) 的位置,这个你就依次交换 \(n\) 与 \(i_1\),\(n\) 与 \(i_2\),\(n\) 与 \(i_3\),……,\(n\) 与 \(i_k\) 位置上的值即可,这样既消灭了所有与 \(n\) 有关的逆序对,又实现了归纳。
8. CF1411F The Thorny Path
一道感觉难度中上的分类讨论题。
首先特判掉 \(n=1\) 的情况,直接输出 1 0
即可,没啥好说的。
根据这篇博客证明的定理,根据 \(n\) 模 \(3\) 得到的余数,最后我们拆分成的置换环大小可能的情况如下:
- 如果 \(n\equiv 0\pmod{3}\),那么最后肯定剩下 \(\dfrac{n}{3}\) 个大小为 \(3\) 的置换环。
- 如果 \(n\equiv 1\pmod{3}\),那么最后肯定剩下 \(\dfrac{n-4}{3}\) 个大小为 \(3\) 的置换环和两个大小为 \(2\) 的置换环,或者 \(\dfrac{n-4}{3}\) 个大小为 \(3\) 的置换环和一个大小为 \(4\) 的置换环。
- 如果 \(n\equiv 2\pmod{3}\),那么最后肯定剩下 \(\dfrac{n-2}{3}\) 个大小为 \(3\) 的置换环和一个大小为 \(2\) 的置换环。
考虑根据 \(n\) 模 \(3\) 得到的余数进行分类讨论:
-
如果 \(n\bmod 3=0\) 那好办,对于每个置换环我们肯定会先贪心的多拆些 \(3\) 出来,然后剩余的大小为 \(1,2\) 的置换环肯定是先 \(1\) 和 \(2\) 互相匹配,剩余落单的 \(1\) 或落单的 \(2\) 匹配,如果落单的是 \(1\),那么设 \(1\) 的个数为 \(c\),那么处理剩余 \(1\) 的最小交换次数为 \(\dfrac{2}{3}c\),如果落单的是 \(2\),那么设 \(2\) 的个数为 \(c\),那么处理剩余 \(2\) 的最小交换次数为 \(c\)。
-
如果 \(n\bmod 3=2\) 也比较容易,我们枚举最后一个 \(2\) 从哪里来,我们设所有置换环大小分别为 \(s_1,s_2,\cdots,s_k\),那么如果 \(\exists j,s.t.s_j\equiv 2\pmod{3}\),那么我们直接从这个置换环中拆出一个大小为 \(2\) 的置换环即可,否则我们就从两个大小模 \(3\) 余 \(1\) 的置换环中各拆出一个 \(1\) 出来。然后对剩余部分跑 \(n\bmod 3=0\) 的情况即可。
-
比较棘手的是 \(n\bmod 3=1\) 的情况,按照 \(n\bmod 3=2\) 的套路,我们枚举最后的零头(也就是一个大小为 \(4\) 的置换环)的出处,有以下五种可能:
- 从一个大小 \(\ge 4\) 且大小模 \(3\) 余 \(1\) 的置换环中切出来。
- 从两个大小模 \(3\) 余 \(2\) 的置换环中切出来。
- 从一个大小模 \(3\) 余 \(2\),两个大小等于 \(1\) 的置换环中切出来大小为 \(2\) 的置换环,再合并两个大小为 \(1\) 的置换环为一个大小为 \(2\) 的置换环。
- 从一个大小为 \(3\) 的倍数的置换环中切出大小为 \(3\) 的置换环,再与一个大小为 \(1\) 的置换环合并成一个大小为 \(4\) 的置换环。
- 由四个大小为 \(1\) 的置换环合并成两个大小为 \(2\) 的置换环。
仿照 \(n\bmod 3=2\) 的情况分类讨论一下即可。
我能说你会了 \(n\bmod 3=2\) 的情况不会讨论 \(n\bmod 3=1\) 的情况就有点不太应该了吗?
9. CF1381C Mastermind
首先,读完题目我们可以很自然地产生这样一个感觉:当 \(y\) 固定时,肯定是 \(x\) 越大,越有可能存在合法的解,因此我们肯定每次会想着贪心匹配出现次数最多的数。
我们不妨先考虑以下弱化版本:\(x=0,y=n\),那么显然,如果出现次数最多的数的出现次数乘 \(2\) 大于 \(n\) 那答案就是 NO,否则我们将所有数按照其出现次数排成一排,譬如 \(1,2,3,1,2,1,2\) 排成一排就是 \(2,2,3,3,1,1,1\),然后我们先用出现次数最多的数去匹配前面的数,然后对于出现次数不是最多的数,我们就按照它们在上述序列中的顺序依次往上填,譬如在上面的例子中,填出来的序列就是 \(1,1,1,2,2,3,3\),然后对应位置上的数依次匹配即可。
接下来考虑原问题,根据上面的推论,我们肯定希望出现次数最多的数的出现次数尽可能小,因此对于 \(x\) 个 \(a_i=b_i\) 的 \(i\),我们肯定会尽量选择出现次数最多的值,这个可以 set 维护。比较困难的是 \(n-y\) 个不出现在原序列中的数即可,由于我们可以填的数的范围为 \([1,n+1]\),因此必然存在一个数 \(\in[1,n+1]\) 且没有在 \(a\) 中出现过,我们假设该数为 \(X\),记 \(mx\) 为 \(a\) 序列中出现次数最多的数的出现次数,那么可以发现,如果 \((n-x-mx)+(n-y)<mx\),那答案就是 NO,否则,我们还是将剩余未被匹配的数按照上面的方式排成一列,即 \(1,2,3,1,2,1,2\) 排成 \(2,2,3,3,1,1,1\),然后我们从后往前填 \(X\),有多少个 \(n+1\) 就填多少个,然后对于出现次数最多的数,我们从前往后填,填到出现次数最多的数用完了或者下一个匹配的数就是出现次数最多的数为止,然后对于剩余的数,再按照顺序填补剩余的空位,这样说的可能不太清楚,举个例子,如果序列为 \(1,2,2,3,3,3,3,3\),且 \(n-y=2\),那么我们先从后往前填两个 \(X\),现在 \(b\) 序列变为 \(?,?,?,?,?,?,X,X\),然后我们从左往右填 \(3\),填上 \(3\) 个 \(3\) 以后序列变为 \(3,3,3,?,?,X,X\),由于如果我们在第四个问号处填 \(3\) 就会出现自己与自己匹配的情况,因此我们只能填三个 \(3\),最后填补剩余空位,除去出现次数最多的数之后,剩余的序列是 \(1,2,2\),我们就按顺序填即可,得到 \(3,3,3,1,2,X,X\),符合题意。
时间复杂度 \(n\log n\)。
10. CF1214F Employment
将 \(a,b\) 从小到大排序,下面默认 \(a_i\le a_{i+1},b_i\le b_{i+1}\)
首先考虑一条链的情况如何处理,可以证明,对于一条链的情况,最小代价就是将 \(a\) 数组与 \(b\) 数组分别排序之后,对应项相减的绝对值之和,证明可用调整法,对于四个数 \(x,y,a,b\),如果 \(x\le y,a\le b\) 成立,那么一定有 \(|x-a|+|y-b|\le|x-b|+|y-a|\)。
接下来考虑环上的情况,我们再次猜测一个性质,就是如果我们假设 \(a_1\) 对应的人选择了 \(b_p\),那么 \(a_2\) 必然选择 \(b_{p+1}\),\(a_3\) 选择 \(b_{p+2}\),以此类推。因此考虑枚举断点 \(i\) 然后依次计算,暴力复杂度 \(\Theta(n^2)\) 显然一脸过不去的样子。不过发现在每对距离求解的式子中,\(a_i\) 的贡献只有 \(a_i,-a_i,m-a_i\) 三种,\(b_i\) 也同理,因此考虑枚举 \(a_i\),然后二分找到满足 \(a_i\) 的贡献为 \(a_i,-a_i,m-a_i\) 时,断点 \(p\) 的区间,然后一遍差分即可求出当断点 \(p\) 为 \(1,2,3,\cdots,n\) 时,所有人移动的最短距离之和。
时间复杂度 \(n\log n\),细节略有点多(
11. CF1372E Omkar and Last Floor
首先看到类似于 \(f(x)=x^2\) 这样的凸函数,我们可以很自然的往贪心的方向联想,具体来说对于某一列,我们感性的理解一下,如果它已经填了比较多的 \(1\),那么我们会尽可能在这一列上多填 \(1\),而不是再在其它列上填 \(1\)。
受到这个思想的启发,我们可以想出如下的贪心:我们选择一列,然后考察所有区间,如果该区间中当前没有填 \(1\),并且我们选择的这一列属于这个区间,那么我们就在这个区间上填上 \(1\),否则我们不对该区间进行任何操作。然后递归地对剩余地矩阵进行操作即可。
考虑区间 dp 优化上述过程。我们设 \(dp_{l,r}\) 表示当前操作了 \([l,r]\) 中的列,恰好所有包含于 \([l,r]\) 中的区间中有位置被填上 \(1\) 的最大权值之和,那么显然有转移 \(dp_{l,r}=\max\limits_{k=l}^rdp_{l,k-1}+dp_{k+1,r}+s_{k,l,r}^2\),其中 \(s_{k,l,r}\) 表示有多少个区间 \([l’,r’]\subseteq[l,r]\),且 \(k\in[l’,r’]\)。这个可以前缀和求出,时间复杂度 \(nm^2+m^3\)。
12. CF1430F Realistic Gameplay
考虑我们应采用如何的策略。首先只要我们枪中还有弹,并且前面还有怪没被杀死,那么我们肯定会一直开枪。如果我们当前这波怪没有打死,并且枪中没弹了,那我们肯定会换弹,唯一不确定的事情是打完当前这波怪之后我们换不换弹,如果我们换了弹,那么带来的后果有两个,一是原来的弹被浪费,二是由于 \(l_{i+1}\ge r_i\),因此如果换弹的时刻刚好是 \(r_i\),而 \(l_{i+1}=r_i\),那就会导致下一波怪只能从 \(l_{i+1}+1\) 时刻开始才能打。因此考虑 DP。\(dp_{i,j}\) 表示打第 \(i\) 波到第 \(n\) 波的怪,第 \(i\) 波怪从时刻 \(l_i+j\) 才能开始打,目前弹夹是满的,最少要花费多少弹才能打死所有怪,其中 \(j\in\{0,1\}\),枚举下一次什么时候把当前的这波怪打完后换了弹夹即可实现 \(\Theta(n^2)\) 求解 DP 数组。
据说有线性做法?orzorz(
13. CF1493E Enormous XOR
诈骗题一道(
首先特判掉 \(r=0\) 的情况。
如果 \(l\) 的最高位为 \(0\),那么由于 \(r\) 的最高位为 \(1\),答案显然是 \(111…11\),构造 \(l=2^{n-1}-1,r=2^{n-1}\) 即可。
如果 \(l\) 的最高位为 \(1\),先特判掉 \(l=r\) 的情况,此时答案显然就是 \(l\)。
不难注意到一个性质,就是对于偶数 \(x\),有 \(x\oplus(x+1)=1\),因此我们如果去掉 \([l,r]\) 中所有满足 \(x\) 为偶数的相邻对 \((x,x+1)\),那最后必定剩下 \(0\) 或 \(1\) 或 \(2\) 个数以及一车 \(1\)。而显然如果最后剩两个数肯定是不优的,因为这样最高位必定为 \(0\),\(0\) 个数的情况只可能是 \(0/1\) 也不太行,因此只可能是一个数的情况最优,而显然我们会想让剩下的那个数为 \(r\),然后剩下的一车 \(1\) 的奇偶性与 \(r\) 奇偶性不同,这样异或起来可以达到理论上界 \(r\text{ or } 1\),但是这样有可能是不可行的。具体来说,如果 \(r\) 本身就是奇数那取 \([r,r]\) 即可达到理论上界,如果 \(r\) 是偶数,且 \(l\le r-2\) 那取 \([r-2,r]\) 也可以达到理论上界,但如果 \(r\) 是偶数且 \(l=r-1\) 那最大值只有 \(r\),达不到 \(r+1\),特判一下即可。
14. CF1492E Almost Fault-Tolerant Database
首先显然答案数组可以在第一行的基础上修改两个元素得到,因此考虑以第一行为基准,求一遍第一行与其余行有多少个不同的元素。
如果存在一行,满足第一行与该行不同元素个数 \(\ge 5\),答案就是 NO。
如果与第一行不同元素最多的行与第一行的不同元素个数 \(\le 2\),直接输出第一行即可。
如果与第一行不同元素最多的行与第一行的不同元素个数 \(=4\),那么可能成为答案的数组显然只有 \(6\) 个,依次 check 一遍即可。
如果与第一行不同元素最多的行与第一行的不同元素个数 \(=3\),我们假设第 \(i\) 行与第 \(1\) 行有 \(x,y,z\) 三个元素不同,那么我们对于所有 \(3\times 2\) 种情况(\((x,y),(x,z),(y,x),(y,z),(z,x),(z,y)\)),依次检验一遍,具体检验方法是,以 \((x,y)\) 为例,先假设 \(ans_x=a_{1,x},ans_y=a_{i,y}\),然后扫一遍整个矩阵,如果不存在某一行与 \(ans\) 不同元素数量 \(\ge 3\) 就输出 \(ans\),否则我们假设第 \(j\) 行与 \(ans\) 不同元素数量 \(\ge 3\),那么我们令 \(ans_z=a_{j,z}\),然后再跑一遍即可。
时间复杂度 \(\Theta(18nm)\)。
15. CF1487F Ones
小清新数位 dp 题,怎么混进我的 blog 的(bushi
考虑从高位到低位确定每一位 \(d\),总共加/减了多少次 \(\dfrac{10^{d+1}-1}{9}\),也就是 \(d\) 个 \(1\) 组成的数,注意到如果我们钦定到第 \(d\) 位,那么此时的 \(n\bmod 10^d\) 可以用两个参数 \(c,p\) 来描述,即设 \(n’\) 表示此时的 \(n\),那么有 \(n\equiv (-1)^pn’+c·\dfrac{10^{d+1}-1}{9}\pmod{10^d}\)。这样就可以 DP 了,设 \(dp_{d,c,p}\) 表示目前考虑到第 \(d\) 位,高于 \(10^d\) 的位都已被清零,目前 \(n\equiv (-1)^pn’+c·\dfrac{10^{d+1}-1}{9}\pmod{10^d}\),最少需要多少次操作才能将 \(n\) 变为 \(0\),转移就枚举如何将 \(10^d\) 位变成零即可,一种是直接减若干次 \(\dfrac{10^{d+1}-1}{9}\),还有一次是先用 \(\dfrac{10^{d+2}-1}{9}\) 减去 \(n\),再减去若干次 \(\dfrac{10^{d+1}-1}{9}\),两种情况分别讨论一下即可,比较烦的一点是要手写高精。
时间复杂度 \(9\log_{10}(n)^3\),常数很小。
16. CF1422E Minlexes
首先吐槽一句,这题 pretest 真是……写了一个完全错误的做法竟然能一连艹过前 45 个点……出题人怕不是用脚造数据,\(n=4\) 的情况我原来写的做法都有锅
考虑 DP。\(dp_i\) 表示 \([i…n]\) 后缀的答案,那么分两种情况转移:
- \(s_i\ne s_{i+1}\),显然 \(s_i\) 必须保留,故 \(dp_i=s_i+dp_{i+1}\)
- \(s_i=s_{i+1}\),此时有两种可能,要么删掉 \(i,i+1\),\(dp_i=dp_{i+2}\),要么保留 \(s_i\),\(dp_i=s_i+dp_{i+1}\),因此只要对上述两个 \(dp\) 值取个 max 即可。
对于第一种情况,手写一个结构体保存每个字符串前后 10 个字符即可 \(\mathcal O(1)\) 插入。比较麻烦的是第二种情况。直接比较是平方的,一脸过不去的样子。不过注意到在头部插入一个字符后字典序变小,等价于对于从左往右数第一对不同的字符 \(i,i+1\),满足 \(s_i<s_{i+1}\),因此在结构体中额外记录一个变量,表示第一对相邻且不同的字符的大小关系即可。
时间复杂度 \(\mathcal O(n)\)。
17. CF1420E Battle Lemmings
首先看到交换次数以及这题 \(n\le 80\) 的数据范围,我们可以很自然地想到将交换次数放入 DP 状态的套路,即设 \(dp_{x,y,k}\) 表示目前填了 \(x\) 个 \(0\),\(y\) 个 \(1\),逆序对个数为 \(k\),并且最后一位为 \(1\),最多能有多少对 \((i,j)\) 满足 \(a_i=a_j\) 且 \([i+1,j-1]\) 中所有数不全为零,转移就枚举下一段 \(0\) 的长度 \(len\),那么有 \(dp_{x+len,y+1,k’}\leftarrow dp_{x,y,k}+len·x\),其中 \(k’=k+\sum\limits_{i=1}^{len}\max(pre_{i+x,0}-y,0)+\max(pre_{y+1,1}-(x+len),0)\),其中 \(pre_{i,0}\) 表示原序列中第 \(i\) 个 \(0\) 前面有多少个 \(1\),\(pre_{i,1}\) 表示原序列中第 \(i\) 个 \(1\) 前面有多少个 \(0\)。时间复杂度 \(n^5\),但由于常数极小,可以通过。
实际上这题还有 \(n^4\) 的做法,然鹅大概由于那天肝了一道 287 行代码 10000+ 个 B 的毒瘤题,这个做法就鸽掉了
18. CF1225F Tree Factory
一开始猜了个错的结论(按子树 size 贪心),然后 WA 6,不愧是我(
首先答案下界显然是 \(n-\max\limits_{i=0}^{n-1}dep_i\),其中 \(dep_i\) 表示 \(i\) 到根节点路径上的点数,因为每次操作最多使整棵树深度最深的节点的深度减少 \(1\)。考虑构造使其达到这个下界。
我们对整棵树进行一遍 DFS,当我们 DFS 到点 \(u\) 时,我们将每个节点所有儿子按照其 \(mxdep\) 从小到大排序,然后每次按 \(mxdep\) 从小到大的顺序依次遍历每个儿子,假设当前遍历到节点 \(v\),那么我们就将当前链上端的 \(siz_v\) 个节点做成 \(v\) 子树的形态,如果 \(v\) 不是最后一个儿子,那么我们就不断执行操作上推这条链上第 \(siz_v+1\) 个节点下端的链直到这个点的父亲为 \(u\) 为止,不难发现该做法的时间复杂度与长链剖分复杂度类似,具体来说,对于一条链,假设其链顶节点为 \(u\),其父亲为 \(f\),那么当我们 DFS 到 \(f\) 时,会进行 \(mxdep_u\) 次上推操作,因此操作次数就是所有长链的长度之和,根据长链剖分那套理论可知所有长链的长度之和为 \(n\)。特别地,\(1\) 所在的长链是不会产生贡献的,因此需减去 \(mxdep_1\),由此可知操作次数为 \(n-mxdep_1\)。
19. CF650E Clockwork Bomb
首先如果一条边在两棵树中都出现过,那么我们肯定不会选择断掉这条边,因此我们考虑将这些边的两个端点 merge 起来。我们记这样的边的条数为 \(c\),那么答案的下界显然为 \(n-1-c\),我们还是通过构造达到这个下界。
我们称缩点过后的第一棵树为 \(T_1\),缩点过后的第二棵树为 \(T_2\),两棵树都以 \(1\) 为根节点。那么我们找出 \(T_1\) 的一个叶子节点 \(x\),找出它在第二棵树上对应的节点 \(y\)。我们断开 \(x\) 在第一棵树上与其父亲之间的边,并连上 \(y\) 在第二棵树上与其父亲之间的边——显然,由于 \(x\) 是叶子节点,此时 \(y\) 与其在第二棵树上的父亲在第一棵树中不在同一连通块中,因此这样一断一连并不会出现环,这样我们就通过一次操作使同时在两棵树中的边数加一,此时我们就可以在两棵树中把新加的边用并查集合并起来,如此归纳下去即可。
具体实现时可对第一棵树进行一遍 DFS,遍历一个点 \(x\) 的子节点 \(y\) 时,我们考察 \(x,y\) 是否在并查集同一连通块中,如果在则忽略它不管,否则我们找到 \(y\) 所在并查集中第二棵树上深度最小的节点 \(u\),然后合并 \(u\) 与 \(u\) 在第二棵树上的父亲。
时间复杂度 \(n\alpha(n)\)。
20. CF1469F Power Sockets
嗯没错就是我现场 AC 的那道 edu F,现在我们来用复杂度更优秀的做法来水这道题(
首先讲讲我赛时的做法,首先很明显的一个事实是,我们加入一条链的时候,肯定会选择将链的中点与当前树中深度最浅的白点连接,那我们就用线段树模拟这个过程呗,设 \(f_i\) 表示距离为 \(i\) 的白点个数,那么我们将链按长度从小到大排序,每次在线段树上二分找到第一个 \(f_i\) 非零的位置,将其减去 \(1\),然后执行两遍区间加。然后每次加入完一条链就再进行一遍线段树二分找出第 \(k\) 个白点的位置更新答案即可。
这样复杂度是 \(n\log n\) 的,常数较大。我们考虑复杂度更优秀(至少常数更小)的做法:不难发现,每次我们找到的 \(f_i\) 非零的位置是单调不降的,这让我们很自然地联想到双指针,具体来说我们每次区间加时维护序列的差分数组,然后每次加入一条链时双指针找到下一个非零的位置,同时再开一个指针维护第 \(k\) 近的白点位置,这样除去排序可以做到线性,使用基数排序可使整个程序做到线性。
21. CF1394D Boboniu and Jianghu
首先吐槽一句,这题的数据有亿点点水啊,一开始写了个 \(\sum deg^2\) 的做法竟然 AC 了(
首先考虑如果这题 \(h_i\) 互不相同如何解决,我们设 \(dp_i\) 表示将 \(i\) 子树中的边以及 \(i\) 与其父亲的边划分成若干条链的最小权值之和,考虑如何转移,我们枚举 \(u\) 的所有儿子 \(v\),那么显然我们可以将 \((u,v)\) 这条边分为两类:\(h_u>h_v\) 和 \(h_u<h_v\)。我们首先将所有 \((u,v)\) 所在的链向上延伸一格,此时我们多余的贡献就是 \(a_u\) 乘以点 \(u\) 儿子的个数,但是这样不见得是最优策略,我们可以选择将一个 \(h_u>h_v\) 的链与一个 \(h_u<h_v\) 的链合并成一条链,这样我们可以少一个 \(a_u\) 的代价。如果我们记 \(h_u>h_v\) 的儿子数为 \(c_1\),\(h_u<h_v\) 的儿子数为 \(c_2\),那么我们最多可以合并 \(\min(c_1,c_2)\) 次,可以减少 \(\min(c_1,c_2)·a_u\) 的代价。此外,如果 \(u\) 不是根节点,我们还要选择一条链向上延伸,这里有两种选择,要么直接 \(u\) 单独成一条链,代价 \(a_u\),要么选择一条链向上延伸,这条链不参与匹配,如果 \(h_{fa_u}>h_u\),那么剩余的链还能匹配 \(\min(c_1-1,c_2)\) 次,否则剩余的链还能匹配 \(\min(c_1,c_2-1)\) 次。
接下来考虑没有 \(h_i\) 互不相同的条件怎么办,显然对于 \(h_u=h_v\) 的 \((u,v)\),它既可以充当 \(h_u>h_v\) 的链,也可以充当 \(h_u<h_v\) 的链,我们就设 \(dp_{u,0/1}\) 表示匹配了 \(u\) 子树内的边,\(u\) 向上延伸的链为单调不增/单调不降的链的最小代价。考虑如何转移,我们枚举 \(u\) 的儿子 \(v\),然后先假设所有 \(v\) 都选择 \(dp_{v,1}\),将所有儿子按 \(dp_{v,0}-dp_{v,1}\) 排序,然后按照套路还是枚举选择了多少个儿子 \(v\) 满足 \((u,v)\) 属于一个单调不增的链,然后 \(\mathcal O(1)\) 计算 DP 值即可。
时间复杂度 \(\Theta(n\log n)\)
22. CF524F And Yet Another Bracket Sequence
首先考虑一个非常重要的性质:一个字符串可以仅通过 cyclic shift 变成 RBS,当且仅当括号串中左右括号个数相等。必要性显然,充分性证明大概就可将一个括号序列看成一个每段斜率都是 \(\pm 1\) 的折线,然后取折线最低处为起点即可使折线上处处高度高于起点。
有了这个性质之后,最少添加的括号的个数就很好确定了,设 \(c\) 为左括号个数减去右括号个数,那么最少需要添加 \(|c|\) 个括号。而关于字典序最小的序列,我们肯定会贪心地选择在序列开头添左括号 / 在序列末尾添右括号,这样括号序列字典序最小,就等价于去掉新添加的括号后,得到的括号序列字典序最小,因此可以直接枚举端点,ST 表判断括号序列是否合法,后缀排序 / 哈希判断字典序大小。时间复杂度 \(\Theta(n\log n)\)。
23. CF1601D Difficult Mountain
首先看到类似这样给定几个二元组/三元组,要按顺序选出一些元素满足个什么条件,求选出元素个数的最大值的题目,我们一般考虑将这些二/三元组按个什么东西为关键字排个序,使得在最优策略中我们肯定在排好序的数组中中从前往后选,这样我们就可以进行线性 DP 了。此题也不例外,经过一番观察我们发现如果 \(p_i·a_i<p_j·a_j\),那么 \(i\) 一定比 \(j\) 先爬山,一个比较感性的理解方式是,如果 \(p_ia_i<p_ja_j\),那么必然有 \(p_i<a_j\) 或 \(a_i<p_j\),对于前者,后一个人爬完了前一个人肯定不会爬,因此我们肯定贪心地把后一个人安排在后面,对于后者,前一个人是否成功登山对后一个人的情况不会产生影响,可以放心大胆地把它放在前面。
这样就可以 DP 了。设 \(dp_i\) 表示当前山的高度为 \(i\) 最多有多少个人能成功登山,离散化+线段树优化 DP 即可,具体来说如果 \(p_i<a_i\) 那我们求 \([0,p_i]\) 的区间最大值然后令 \(dp_{a_i}\) 对该最大值取 \(\max\),如果 \(p_i\ge a_i\) 则令 \([a_i+1,p_i-1]\) 区间加 \(1\),然后求一下 \([0,a_i]\) 的区间最大值并令 \(dp_{a_i}\) 对该最大值取 \(\max\),时间复杂度 \(\Theta(n\log n)\)。