MX 炼石 2025 NOIP #5
串串好次。
笑点解析:这到底是哪一年的炼石计划。


2025 --【炼石计划 NOIP】-- 第五套
时间:4h (2025.09.11 14:00~18:00)
题目数:4
难度:
| A | B | C | D |
|---|---|---|---|
| \(\color{#52C41A} 绿\) | \(\color{#52C41A} 绿\) | \(\color{#9D3DCF} 紫\) | \(\color{#BFBFBF} ?\) |
| *1900 | *1700 | *2700 | *? |
估分:60 + 80 + 32 + ? = 172+?
得分:40 + 60 + 32 + 10 = 142
Rank:42/216
场祭
读题。怎么两道串串题。
开 A,期望 dp,推了一会儿发现可以令 \(f_{i,j}\) 表示第 \(i\) 个时刻有 \(j\) 个人选 A 的概率,转移:
答案就是概率乘上贡献。这样是 \(O(nm)\) 的而且发现非常不好优化,数据结构做不了,只维护后缀和也做不了。于是就这么写了个暴力走人了。
大概有 80pts 吧,如果不卡常的话。
B 一眼 KMP,但是发现要维护 fail 树的子树大小支持动态加叶子,显然是 LCT 但是我不会,于是只打了 60pts 的暴力和 20pts 的离线 dsu on tree。
还剩 1h+。
C 先把 32pts 的暴力打了。然后找性质,发现 \(k=2\) 时每个 \(0 \sim 2^k - 1\) 的序列都是 \(0 \sim 2^{k-1} - 1\) 的序列后面拼上自己的按位取反之后的结果,但是不知道有啥用。
D 性质 A 分这么多,不过好像很多细节比较麻烦,没时间了直接 random_shuffle 相信随机数吧。应该是可以有分的。
补题
草草草,A 只得了 40pts,多测 \(\sum n + \sum m\) 太大导致的,早知道就直接预处理所有 \(n\) 的答案了,起码能多拿 10pts。
A 还有逆天注意力做法……注意到如果稍微换一下 dp 状态,令 \(f_{i,j}\) 为一共有 \(i\) 个人,\(j\) 个不选 A 的概率,那么:
观察到:
于是答案:
直接前缀和算一下后面拿两个 \(\sum\) 就好了。注意到 \(n=1\) 需要特判。
但是我们不具有这样的观察力,所以考虑组合意义。
直接做不可以,因为每种情况的概率不相同。
考虑转化。首先我们还是要求一共有 \(i\) 个人,\(j\) 个不选 A 的概率。先把 \(n\) 个选手放到一个序列上,编号分别为 \(\color{#66CCFF} 1 \sim n\):
然后每加入一个观众 \({\color{#EEAADD}i}\),就相当于在当前序列中任选一个位置,把 \({\color{#EEAADD}i}\) 插入这个位置后面,例如:
可以发现,最终形成的是一个 \({\color{#66CCFF}1} \sim {\color{#EEAADD}i}\) 的排列,其中 \(\color{#66CCFF} 1 \sim n\) 这 \(n\) 个数相对有序。显然这样形成的每个序列和每种情况构成双射,且出现的概率相同。
然后计数:
- 总方案数:
- 我们钦定 \(\color{#66CCFF}1\) 在首位,为了使 \(\color{#66CCFF} 1 \sim n\) 相对有序,需要在剩下 \(i-1\) 个位置里选择 \(n-1\) 个来放 \(\color{#66CCFF} 2 \sim n\),方案数也就是 \(\binom {i-1} {n-1}\)。
- 剩下的 \(i-n\) 个元素 \(\color{#EEAADD} n+1 \sim i\) 则可以任意排列,方案数为 \((i-n)!\)。
- 容易发现这样计数是不重不漏的,所以总方案数即为 \(\binom {i-1} {n-1} \times (i-n)!\)。
- 合法方案数:
- 类似地,因为有 \(j\) 个人不选 A,所以可以钦定 \(\color{#66CCFF}2\) 后面有 \(j-1\) 个元素,那么在这 \(j-1\) 个元素中,要选 \(n-2\) 个来放 \(\color{#66CCFF} 3 \sim n\),方案数为 \(\binom {j-1} {n-2}\)。
- 剩下的 \(i\) 个,包括 \(\color{#66CCFF}1\) 和 \(\color{#66CCFF}2\) 之间的元素,都可以随便排列,方案数为 \((i-n)!\)。
- 同样,合法方案数即为 \(\binom {j-1} {n-2} \times (i-n)!\)。
于是概率就是合法方案数除以总方案数,把 \((i-n)!\) 约掉得到:
B,草,原来 8e5 也能分块,应该是根号跑不满导致的,下次看到 1e6 甚至 5e6 以下的不会 log 就去想根号吧。
可以根号就简单了,这不随便做。注意到 \(fa_i < i\)(\(fa\) 即 fail 数组),所以连树上分块都不用,直接对原序列分块,维护一个 \(nxt_i\) 表示从 \(i\) 往上跳祖先能跳到的第一个和 \(i\) 不在同一个块内的点,然后修改分别在跳到的所有 \(nxt\) 上打个懒标记,查询直接重构整个块把打的懒标记都跑一遍即可。
C 有点厉害了。
还是先考虑 \(k=2\)。根据上面那个结论,记 \(w_{t,i}\) 为 \(w(i \times 2^t , (i+1) \times 2^t - 1)\),其中 \(i \in \{1,2\}\),那么有:
其中 \(+\) 表示字符串拼接,\(\neg\) 表示取反。
于是,每个 \(w(l_i , r_i)\) 就可以拆成 \(O(\log V)\) 个 \(w_{t,i}\)。
回到 AC 自动机计数的过程,在对 fail 树拓扑排序之前,我们记录的是每个点被直接经过的次数。很难发现如果知道了每个 \(w_{t,i}\) 最终跑到了哪个点上,那么是可以对上面的式子倒着做,也就是倒过来的倍增,来推出自动机上每个点被经过的次数的。
考虑 dp,令 \(f_{x,t,i}\) 为从自动机上节点 \(x\) 开始,跑一遍 \(w_{t,i}\) 最终到达哪个节点,转移还是上面用那个式子倍增,有:
然后倒着倍增,令 \(g_{x,t,i}\) 为从节点 \(x\) 开始,跑一遍 \(w_{t,i}\) 经过的路径上的点需要被加多少次,则有转移:
那么最后把 \(g\) 求完之后,对于所有 \(x,i\) 做一遍 \(cnt_{f_{x,0,i}} \gets g_{x,0,i}\) 即可。注意到并不需要给 \(x\) 加,因为 AC 自动机在匹配文本串的时候是从开始节点的儿子开始的。
剩下的就是板子了。
但是注意到这只是 \(k=2\),不过 \(k>2\) 的做法也比较显然了。
记 \(w_{t,i} = w(i \times k^t , (i+1) \times k^t - 1)\),仍然可以发现:
所以和上面的过程其实没有本质区别。
可是……可是文本串 \(S\) 是由好多个 \(w_{t,i}\) 拼起来的呀,那如果一个模式串横跨了好几个 \(w_{t,i}\) 咋办啊?这也不能暴力,然后 ta 还不给下发 std 这叫我补个毛线()
D 是神仙构造还不仅仅是神仙构造还是神仙 ds。虽然构造可爱吧但是是真的补不动。
天依宝宝可爱!

浙公网安备 33010602011771号