草稿纸
关于难度
- \(\textbf{Easy}\):我是 zak,我一眼秒了,我觉得这题没啥技巧啊!
- \(\textbf{Medium}\):完全自己想出,但想了较长时间。
- \(\textbf{Hard}\):不完全是自己想出。
\([0, 1]\) 表示在同档题中的难度。
CF2152G \([\textbf{*Easy 0.5}]\)
我们称有怪物的点为黑点。直接硬维护,一个点有贡献当且仅当它是黑点且它下面没有其它黑点。在 dfs 序上用线段树,维护区间内极深黑点数量、极深白点数量,修改时子树内直接打 swap 的标记,子树外最多影响两个点,即子树全白时极深的黑点与子树全黑时极深的白点(修改前、修改后各至多一个),容易判断这样点的存在性,如果存在就倍增往上跳找到该点即可,复杂度 \(\mathcal{O}(n + q \log ^ 2 n)\)。
有更聪明的做法。考虑括号序,只保留黑点的括号,则答案就是 () 的数量。直接用线段树维护括号序,复杂度 \(\mathcal{O}(n \log n)\)。
AGC032D \([\textbf{*Medium 0.2}]\)
我们发现 \((p_l, p_{l + 1}, \cdots, p_r)\) 循环左移为 \((p_{l + 1}, p_{l + 2}, \cdots, p_r, p_l)\) 等价于将 \(p_l\) 插入至 \(p_r\) 之后,即向右插入。同理循环右移等价于向左插入。
考虑钦定不移动的元素,必然构成一个上升子序列。对于需要操作的元素,考虑向左、向右插入的限制。设不移动的元素下标为 \(i_1 < i_2 < \cdots < i_m\),记 \(i_0 = 0, i_{m + 1} = n + 1\),对于 \(i_j < x < i_{j + 1}\),若 \(p_x > p_{i_{j + 1}}\) 则必然向右插入,若 \(p_x < p_{i_j}\),必然向左插入。我们显然可以不妨假设不移动的元素构成一个极长上升子序列,故不会出现 \(p_{i_j} \le p_x \le p_{i_{j + 1}}\) 的情形(若出现可随意钦定向左或向右插入,显然更劣,故 dp 时不用考虑极长的条件)。考虑 dp,记 \(dp_{i, j}\) 为考虑 \(p_1, p_2, \cdots, p_i\),在其中上升子序列最后一项为 \(j\) 的最小代价。转移时 \(a_i < j\) 则向左插入,\(a_i > j\) 则可选择作为下一项或向右插入,复杂度 \(\mathcal{O}(n ^ 2)\)。
CF1913F \([\textbf{*Easy 0.8}]\)
考虑把一个位置改掉的贡献,按传统技巧在每两个字符中间插 #,那么对于以 \(i\) 为中心,半径为 \(L_i\) 的极长回文串,只有修改 \(s_{i - L_i}\) 或 \(s_{i + L_i}\) 会让以 \(i\) 为中心的极长回文串变长。修改方法显然是确定的,增量使用二分哈希计算即可。对于修改后破坏的回文串数量,按照修改位置在回文中心的左侧、右侧分类处理,分别递推即可。求字典序最小的解也是容易的,总复杂度为 \(\mathcal{O}(n \log n + n |\Sigma|)\)。写代码时注意递推的细节。
CF1946F \([\textbf{*Medium 0.5}]\)
对 \(r\) 扫描线,考虑以 \(a_r\) 为右端点的合法子序列。记 \(f_{i, j}\) 表示 \(a_i\) 开头,\(a_j\) 结尾的合法子序列数,我们发现状态数是 \(\mathcal{O}(n \log n)\) 的。转移即为 \(f_{i, j} = \sum\limits_{a_i | a_k, a_k | a_j, i \le k < j} f_{i, k}\),注意到转移是 \(\mathcal{O}(n \log ^ 2 n)\) 的,于是暴力转移即可。对于答案,用树状数组维护即可,总复杂度为 \(\mathcal{O}(n \log ^ 2 n + q \log n)\),感觉注意到暴力是对的有点难阿。
QOJ18298 \([\textbf{*Easy 0}]\)
直接按子树大小贪心即可。
CF2233E2 \([\textbf{*Easy 0}]\)
显然要求等价于两两不同、没有 \(0\)、二进制每位 \(1\) 的个数为某个定值(即 \(1, 2, \cdots, n\) 二进制下该位 \(1\) 的个数),然后就随便做了。
P15534 \([\textbf{*Medium 0.4}]\)
一个有趣且重要的观察:若 \(x\) 从 \(u\) 前往 \(v\) 后变成了 \(y\),那么 \(y\) 从 \(v\) 前往 \(u\) 后会变成 \(x\)。所以我们可以把 \(u \rightarrow v\) 的路径拆成 \(u \rightarrow LCA(u, v)\),\(LCA(u, v)\),\(LCA(u, v) \rightarrow v\),(注意 \(LCA(u, v)\) 恰操作一次),然后将 \(u \rightarrow LCA(u, v)\) 拆成 \(u \rightarrow 1 \rightarrow LCA(u, v)\),\(LCA(u, v) \rightarrow v\) 拆成 \(LCA(u, v) \rightarrow 1 \rightarrow v\)(这样两边相当于都不对 \(LCA(u, v)\) 操作,也是对的),再那么只需要解决以 \(1\) 为开头或结尾的路径,用主席树维护每个 \(x\) 经过 \(1 \rightarrow u\) 的变化,另一个方向同理,复杂度为 \(\mathcal{O}((n + q) \log n)\),这个可能过不了。离线下来做四遍,用 \(\mathcal{O}(n) - \mathcal{O}(1)\) LCA 可以做到 \(\mathcal{O}(n + q)\)。实测用 \(\mathcal{O}(n \log n) - O(1)\) LCA 是能过的。
P17286 \([\textbf{*Hard 1}]\)
CF2115F2 \([\textbf{*Hard 1}]\)
QOJ16500 \([\textbf{*Medium 0.5}]\)
$\texttt{hint 1}$:两个操作有什么性质 $[\textbf{*Easy 0.2}]$
-
对于操作 \(1\),\(\texttt{he} \to \texttt{she}\):这相当于每次操作在 \(\texttt{he}\) 前加上一个字符 \(\texttt{s}\)。(显然这个 \(\texttt{he}\) 不会被拆掉)
-
对于操作 \(2\),\(\texttt{his} \to \texttt{her}\):由于 \(\texttt{r}\) 是一个无法被操作的字符,所以这相当于用一个 \(\texttt{s}\) 将 \(\texttt{hi}\) 变成了 \(\texttt{he}\),此后进行操作 \(1\)。
总结一下,在进行有限次操作之后,每次操作都会形如在固定的若干个 \(\texttt{he}\) 前分别加上 \(\texttt{s}\),而在此之前,可能有若干个 \(\texttt{hi}\) 后面出现 \(\texttt{s}\),被触发成 \(\texttt{he}\)。
$\texttt{hint 2}$:哪些 $\texttt{hi}$ 在何时会变成 $\texttt{he}$ $[\textbf{*Easy 0}]$
我们发现前面的 \(\texttt{he}\) 不会影响后面的 \(\texttt{hi}\),所以可以从后往前考虑每个 \(\texttt{hi}\)。对于某个 \(\texttt{hi}\),若其后一个字符为 \(\texttt{s}\),则第一次操作后就会变为 \(\texttt{he}\)。否则考虑它的后两个字符,若不为 \(\texttt{hi}\) 或 \(\texttt{he}\),则显然不可能产生 \(\texttt{s}\) 将其变为 \(\texttt{he}\)。若为 \(\texttt{he}\),则第二次操作后可变为 \(\texttt{he}\)。若为 \(\texttt{hi}\),也可从后往前递推求出变为 \(\texttt{he}\) 的时间。
我们发现对于某个 \(k\),操作 \(k\) 次之后的串形如原串加上若干个 \(\texttt{s}\) 的连续段,再将若干个 \(\texttt{is}\) 替换为 \(\texttt{er}\)。我们希望用二分求出第 \(x\) 个位置在哪一个 \(\texttt{s}\) 的连续段之后(或内部)。对 \(k\) 从小到大处理,由于 \(x\) 时刻第 \(i\) 个连续端的长度会形如一个先取 \(0\) 后取 \(x - c\) 的分段函数,用线段树维护连续段长度的前缀和,在每个 \(\texttt{hi}\) 变成 \(\texttt{he}\) 的时刻进行一个后缀加 \(x - c\),查询即为线段树上二分。总复杂度为 \(\mathcal{O}((n + q) \log n)\),难点在写代码。
QOJ16513 \([\textbf{*Medium 0.6}]\)
选出的奶龙下标集合为 \(S\)。若存在 \(i \neq j \in S\) 满足 \(a_i > b_i, a_j > b_j\),则不妨设 \(b_i > b_j\),有 \(a_i > b_i > b_j\),矛盾。故至多存在一个 \(i \in S\) 满足 \(a_i > b_i\)。考虑一个前缀 \([1, k]\) 的答案。
- 若 \(S\) 中元素全部满足 \(a_i < b_i\):设选出的 \(\max\limits_{i \in S} a_i = M\),那么对任意 \(j \neq i \in S\),有 \(a_i < b_j\),又因为 \(a_i < b_i\),有 \(\max\limits_{i \in S} a_i < \min\limits_{i \in S} b_i\)。扫描线时使用权值线段树对每个 \(v\) 维护 \(a_i \le v < b_i\) 的 \(i\) 的个数即可。记这样 \(i\) 的个数为 \(f_v\)。
- 若 \(x \in S\) 满足 \(a_x > b_x\):则对于任意 \(i \neq x \in S\) 都有 \(b_i > a_x > b_x > a_i\)。故 \(|S| \le f_{a_x} + 1\)。故只有 \(f_{a_i} = \max\limits_v f_v\) 且 \(\not \exists 1 \le i \le k\) 使得 \(b_i > a_x > a_i > b_x\) 才可能使答案增大 \(1\)(相对上一种情况来说)。而对于每个满足 \(a_x > b_x\) 的 \(x\),\(\not \exists 1 \le i \le k\) 使得 \(b_i > a_x > a_i > b_x\) 在 \(k\) 取一个前缀时成立。故每个 \(x\),需要将答案和 \(f_{a_x} + 1\) 取 \(\max\) 的 \(k\) 是一个区间(还要要求 \(x \ge k\))。故在扫描线过程中在线段树上维护满足条件的 \(x\) 中 \(f_{a_x} + 1\) 的最大值即可。只需找到对每个 \(x\) 的对应前缀,主席树加二分即可,复杂度为 \(\mathcal{O}(n \log ^ 2 n)\)。
能不能再给力一点?我们继续分析性质。如果答案增大,不仅 \(\not \exists 1 \le i \le k\) 使得 \(b_i > a_x > a_i > b_x\),也 \(\not \exists 1 \le i \le k\) 使得 \(a_x > b_i > b_x > a_i\)。故 \([b_x, a_x]\) 与 \([a_i, b_i]\) 必然包含或相离。又因为如果 \([a_i, b_i] \subseteq [b_x, a_x]\),有 \(f_{a_i} > f_{a_x}\),也无法更新答案。所以我们知道 \(\not \exists 1 \le i \le k\) 使得 \(a_i < b_i\) 且 \(a_i \in [b_x, a_x]\) 或 \(b_i \in [b_x, a_x]\),这样 \(k\) 还是一个前缀,且可以用 ST 表求出。复杂度为 \(\mathcal{O}(n \log n)\)。

浙公网安备 33010602011771号