2026.5.5 模拟赛
https://oj.gxyzh.com/d/hzoj/contest/69f9334ab7358e274b6e8bcf
https://www.luogu.com.cn/contest/211087
这场 T1,T2 较为简单(绿+蓝):分别为 置换、反悔贪心.
IMAWANOKIWA
可以先打表:
| 0 | 1 | 2 | |
|---|---|---|---|
| 0 | 0 | 1 | 1 |
| 1 | 1 | 1 | 2 |
| 2 | 1 | 2 | 1 |
因此可以发现一些神秘性质:
- 当两个数均为 0 的时候才会有 0.
- 没有 0 的时候(即仅有 1,2 的时候),运算是满足结合律的.
但是我们需要更多的性质,下面先直接给出结论:
- 答案为 0:当且仅当所有数字均为 0.
- 答案为 2:序列包含奇数个 2 且没有 0;序列为
11..1120211..11的形式. - 答案为 1:else.
答案为 0,2 的情况比较显然,下面是答案为 1 的情况:
考虑归纳,如果我们能找到一个 0,然后将其左右两边合成,只要左右两边不都是 2,最终就可以合出 1。
假设 0 的个数大于两个,那么选择最左边的 0 即可,右边至少有两个 0,一定可以得到 1;
假设 0 的个数恰好有两个,那么序列 a 一定是 A0B0C 的形式,其中 A,B 都是不存在 0 的序列。如果 B 为 [2],那么先将 B 和旁边一个 0 合成即可得到 A01C 的形式,该形式答案一定为 1;否则左右两个 0 肯定有一个合法。
假设 0 的个数只有一个。如果 0 两边至少有一个不是 2,那么我们就有操作空间了:当 2 有奇数个时,我们让最靠近 0 的 2 把经过的 1 都干掉,与 0 合并。否则我们直接让 0 与它旁边的那个 1 合并。假设这个 0 的左右两边都不合法,那么一定有一边至少有三个 2,我们把最靠近 0 的两个 2 合并,0 两边就至少有一个 1;否则可以直接合出 1。
这样所有情况都被考虑到了,证毕。
(来自出题人的证明)
这样我们就能简单地判断一个字符串的最终合并答案.
如果我们知道一个字符串的以下信息:长度 \(n\),0 2 02 20 串的个数,这样就能 \(O(1)\) 判断.
对于最小的操作序列的构造,可以考虑贪心:
从字符串开头依次判断:合并当前字符,会不会使答案变大,若可以则合并.
这样表面上是 \(O(n^3)\) 的,实际上 \(O(n^2)\) 的:因为可以合并的字符位置一定不超过 3.
证明可以看这篇 文章.
接下来,实现的时候使用 链表 维护字符串就可以了,这样就能做到 \(O(n)\).
魔法少女们
由于 \(f(A)\) 最终要求的是和的形式,因此考虑贡献的处理:
只需要计算每对 \(S_i\) 与 \(T_i\) 对应多少种 \(A\) 就可以.
显然下面要进行分类讨论:
若 \(|S_i|+|T_i|\ge K\):即前后缀拼接会有重叠.
(这一部分是比较好想的,但是难以实现)
现在就会有两个问题:判断 \(S_i\) 与 \(T_i\) 是否合法,\(S_i\) 与 \(T_i\) 拼接之后的字符串是否合法.
对于第一个问题,是比较好解决的,下面以 \(S_i\) 为例:
一个括号序列是否合法,只要保证每一个前缀中 ( 的个数一定大于等于 ) 的个数.
这里将 ( 赋值为 1,) 赋值为 -1,保证前缀和大于等于 0 即可.
对于第二个问题:
判断 \(S_i\) 与 \(T_i\) 能否拼接可以使用 Hashing.
由于 \(S_i\) 与 \(T_i\) 代表的前缀和后缀都合法,因此我们只需要让拼接后的字符串中:( 与 ) 个数相等.
上面的处理,可以考虑枚举 \(S_i\) 与重叠的长度 \(len\),判断有那些 \(T_i\) 满足,可以使用哈希表维护.
(这一步卡了 4 hour,使用手写哈希表,unordered_map 太慢了)
时间复杂度为 \(O(L)\).
若 \(|S_i|+|T_i|<K\):之后的下面为了方便,令 \(k=\frac{K}{2}\).
考虑一个转化:让 \(S_i\) 对应一个点 \(s_i(x_i,y_i)\),其中 \(x_i\) 表示 ( 的个数,\(y_i\) 表示 ) 的个数.
同理令 \(T_i\) 对应 \(t_i(k-x_i,k-y_i)\),其中 \(x_i\) 表示 ( 的个数,\(y_i\) 表示 ) 的个数.
这样 \(S_i\) 与 \(T_i\) 对应的字符串的个数就是 \(s_i\to t_i\) 的路径条数,并始终保证 \(x\ge y\).
这是经典的反射容斥:答案为 \(\binom{x_2-x_1+y_2-y_1}{x_2-x_1}-\binom{x_2-x_1+y_2-y_1}{y_2-1-x_1}\).
直接枚举的话是 \(O(nm)\) 的.
因此我们考虑上面路径统计,其实它还有 dp 解法,而直接 \(dp\) 是 \(O(k^2)\) 的.
这启示我们进行根号分治,设阈值为 \(B\).
但是问题来了,贡献是每对之间都有的,如何进行处理?
由于乘法原理:\((i,j)\) 到 \(t_i\) 的路径条数与 \(dp_{i,j}\) 的乘积,就是 \(s_i\to t_i\) 的路径中必定经过 \((i,j)\) 的条数;考虑如何不重不漏地统计:对一条直线上的 \(dp_{i,j}\) 进行统计,这样就能不重复.
现在就找到了解决方法:对于 \(x_i+y_i\le B\) 的点,使用 dp,得出 \(x+y=B\) 这条直线上的答案,这样是 \(O(B^2)\) 的,直线上有 \(O(B)\) 个点;对于 \(x_i+y_i> B\) 的点,只会有 \(O(\frac{L}{B})\) 个.
具体地,对于 \(S_i\):对于 \(x_i+y_i\le B\) 的点,使用 dp,得出 \(x+y=B\) 这条直线上的答案;对于 \(T_i\):对于 \(x_i+y_i\ge 2k-B\) 的点,使用 dp,得出 \(x+y=2k-B\) 这条直线上的答案;
之后,对于 \(S_i\) 的直线上的点与 \(T_i\) 中直线的点和散点 统计贡献;对于 \(S_i\) 的散点与 \(T_i\) 中直线的点和散点 统计贡献.
计算一下时间:dp 的时间为 \(O(B^2)\),统计直线到散点的时间为 \(O(B\times \frac{L}{B})=O(L)\),统计直线到直线的时间为 \(O(B^2)\),统计散点到散点的时间为 \(O(\frac{L^2}{B^2})\);总的时间复杂度为 \(O(B^2+\frac{L^2}{B^2}+L)\),当 \(B=\sqrt{L}\) 时,有 时间复杂度的理论最优值 \(O(L)\).
(当然上面是整体思路,实现是会有很多特殊情况:\(2k\le B\) 的情况 与 散点在 dp 范围之内时无法在直线上统计)

浙公网安备 33010602011771号