CF1332 简要题解

决定了……以后每场 CF/atc 都写题解好了。

希望不会咕

  • A

注意 \(x_1=x_2\) 或者 \(y_1=y_2\) 的时候任何该方向的移动都不合法即可,其余只需判断终点是否在范围内。

  • B

由于 \(a_i\leq 1000\),且都是合数,因此至少有一个质因子 \(p\leq \sqrt{1000}\leq 32\)。打一下质数表发现恰好 \(11\) 个,对每个质数染色它的倍数即可。

  • C

和字符串完全没关系的一题。由回文串和 border 的性质(题面里都写出来了……)可以直接判断哪些位置必须相等,并查集缩起来之后贪心决定每个块的值即可。

  • D

比较有趣的一题,构造矩阵来 “欺骗” 写假了的 dp。思路是构造一条 \(2^x\) 的路径,并在终点处将它阻断,从而使较低位成为真正的答案。设 \(x=2^{17}\),则 \(k<x\leq 3\times 10^5-k\),有:

\[\left[ \begin{array}{ccc} x+k & k & 0 \\ x & x+k & k\\ \end{array}\right] \]

可以发现,dp 过程中的 \(f_{2, 2}=x, f_{2, 3}=0\),而真正的答案是 \(k\)

  • E

将棋盘黑白染色后,设黑色格子的高度和为 \(b\),白色格子的高度和为 \(w\),考虑两种操作的本质:

  1. \(b, w\) 分别 \(+1\)
  2. \(b\)\(w+2\)

显然操作不会改变 \(|b-w|\) 的奇偶性。

对于 \(nm\) 是奇数的情况,最终 \(|b-w|\) 的奇偶性可以任意,因为黑白格子数必然不同,可以让多出来的格子任意填充。可以发现对于任意的初态都可以构造出解。

对于 \(nm\) 是偶数的情况,显然黑白格子个数相同,也就是说,最终 \(|b-w|\) 必须为 \(0\)。可以发现,对于 \(\frac{nm}{2}\) 个黑格子和 \(\frac{nm}{2}\) 个白格子,都可以任意填充,只需要保证 \(b\equiv w\pmod 2\) 即可。用矩阵快速幂可以加速上述 dp 过程。

  • F

并不算难的树 dp。

\(f_{i, 0/1/2}\) 表示以 \(i\) 为根的子树,只考虑 \(i\) 与儿子之间的边时,\(i\) 点不在生成子图中/在生成子图中,但是不在独立集中/在独立集中的方案数。

转移时枚举 \(i\) 点与儿子之间的边是否被选即可,需要保证每个 \(1/2\) 的状态只在第一次连接与儿子之间的边时被算到。注意如果儿子状态是 \(0\),且这条边被选,则儿子会被加入生成子图,此时还需要根据当前点的状态决定儿子是否在独立集中。转移方程详见代码。

  • G

手玩一下(或者观察到输出总量是 \(kq\) 级别)可以发现,\(k\leq 4\)

对于 \(k=3\) 的情况,不妨设 \(b_1, b_3< b_2\),只需要在每个位置找出左右两边最近的,小于它的数即可。可以用权值线段树维护每个数最后出现的位置,注意到权值下标只需要小于某个值,即单点加整数,维护前缀最大值,因此树状数组也可以胜任。这样只有 \(O(n)\) 个三元组,将每个组挂在 \(b_3\) 的位置,做一遍扫描线即可。\(b_1, b_3>b_2\) 的情况是对称的。

发现合法的 \(k=4\) 一定满足 \(b_1, b_4\in \left(\min(b_2, b_3),\max(b_2, b_3)\right)\)。不妨设 \(b_1\geq b_4\),考虑从左到右枚举 \(b_4\),寻找最靠右的合法 \(b_1\)

由于 \(\min(b_2, b_3)<b_4\leq b_1<\max(b_2, b_3)\),设 \(x\) 是当前位置左边最后一个满足 \(a_x< b_4\) 的位置,发现 \(a_x=\min(b_2, b_3)\) 一定满足条件且最优。可以用 \(k=3\) 时的树状数组简单地找到 \(x\)

对于 \([1, x)\) 的每一个 \(i\),若 \(b_1=a_i\),则需要在它右边找到一个 \(y\) 使得 \(a_i<a_y\),即 \(\max(b_2, b_3)=a_y\)。发现此处的 \(y\) 可以任意选择,只要保证 \(y>i\)\(a_y>a_i\) 即可。注意此处并没有限制 \(x, y\) 的位置关系,因此可以将每个候选的 \(a_i\) 用小根堆维护,在每一次枚举 \(b_4\) 的最后,判断当前位置是否可以成为堆顶 \(a_i\)\(y\)

现在我们需要维护每一个找到 \(y\)\(b_1=a_i\),询问时找出 \(i<x, a_i\geq b_4\)\(a_i\) 中,\(i\) 最大的一个。抽象一下,等于维护一个带权点集,支持插入新点和在一个包含左上角的矩阵中,询问权值最大的一个。

可以直接写一棵树套树,但是常数巨大,不一定能过。

注意到询问是两个前/后缀,因此可以用树状数组维护 \(i\)set 维护 \(a_i\)。具体地,在树状数组的每个位置,维护一个 set<pair<int, int>>,其中 first 代表树状数组该位置对应区间内,某个元素的 \(a_i\) 的值,second 代表它的点权。由于询问的是 first 的一段后缀,有用的 second 必然也是单调的。插入 \((a_i, i)\) 时暴力删掉无用元素即可。复杂度 \(O\left((n+q)\log^2 n\right)\),常数和代码量都较小(就算这样我也写了 3.3K……)。

posted @ 2020-04-01 17:39  suwakow  阅读(305)  评论(0编辑  收藏  举报
Live2D