1 条题解
-
0
题意概述
有 个长度为 的字符串,每个字符串由小写字母和
?组成。
?可以替换为任意小写字母。
问有多少对字符串 (),使得存在一种替换?的方式,使两个字符串完全相同。
问题分析
两个字符串能匹配的条件是:对于每个位置 (),
要么两个字符相同,要么至少有一个是?。
即:不存在某个位置 使得两个字符都是字母且不同。设两个字符串为 和 ,则它们能匹配的充要条件是: [ \forall k,\quad s[k] = t[k] \ \text{或}\ s[k] =\ ? \ \text{或}\ t[k] =\ ? ] 等价地: [ \forall k,\quad (s[k] \neq \ ? \ \text{且}\ t[k] \neq \ ?) \implies s[k] = t[k] ]
暴力方法
枚举所有 对字符串并逐位检查,复杂度 , 可达 ,不可行。
利用 很小的特点
,这提示我们可以用位运算或状态压缩。
考虑对于每个字符串,它在每个位置有三种可能:
- 是某个字母 ()
- 是
?
我们可以将
?视为“任意字母”,所以匹配条件就是:对于所有位置,要么至少一个是?,要么字母相同。
转化为集合包含问题
对于一个字符串 ,定义两个集合:
- 确定位置集 : 中不是
?的位置集合。 - 字母模式 :在确定位置上对应的字母序列(可以压缩成一个整数)。
两个字符串 和 能匹配的条件是:
- 在它们都有确定字母的位置上,字母必须相同。
- 换句话说, 中的位置上, 和 必须一致。
等价类划分
我们可以将每个字符串 映射为一个“模式”:
- 枚举所有可能的位置子集 (),对应 中确定字母的位置集合。
- 在该子集上,对应位置的字母构成一个“确定字母串”。
两个字符串匹配当且仅当:
- 它们在某些位置都确定字母,且这些位置的字母相同。
- 即:存在一个非空位置集合 ,使得 和 在 上的字母完全一致。
更直接的方法:容斥或哈希
因为 很小,可以枚举所有 个位置子集 。
对于每个字符串 ,我们可以计算它在 指定的位置上的“部分字符串”:- 如果 中某个位置在 中是
?,则 在这个 上没有定义(或者视为特殊标记)。 - 否则,取出这些位置上的字母,构成一个字符串 。
两个字符串 和 能匹配的条件是: [ \exists mask,\quad sub(s, mask) = sub(t, mask) \ \text{且} \ mask \subseteq A_s \cap A_t ] 其实等价于:在它们都确定字母的位置上字母相同。
所以我们可以用哈希来统计:
对于每个字符串 ,枚举所有子集 ,将 进行哈希,记录出现次数。
但这样每个字符串要枚举 种子集,最坏 种,,总枚举量约 ,可以接受。
统计配对数量
注意:两个字符串 和 可能在多个 下都满足 ,这会重复计数。
为了避免重复,我们规定:只取 ,即它们都确定字母的位置集合。
在这个 上,它们必须字母一致才能匹配。
算法步骤
- 对每个字符串 ,确定 (哪些位置是字母)。
- 将 在 上的字母串提取出来(长度 ),并编码成一个整数(26 进制或直接字符串哈希)。
- 我们定义一个关键表示:,其中 是 在 上的字母编码。
- 两个字符串 和 能匹配当且仅当:
- 令
- 和 在 上的字母序列相同
等价地,我们可以枚举所有可能的 (),然后考虑所有 包含 的字符串,在 上的字母编码必须相同才能匹配。
具体实现:按 分组
对于每个 ,我们只关心那些 的字符串(即 中所有位置在 中都是字母)。
将这些字符串按照在 上的字母编码分类。
同一类中的任意两个字符串都能匹配吗?
检查:设 和 在 上字母相同,且 ,。
那么对于任意位置 :- 如果 ,则 (字母相同)
- 如果 ,则 或 至少有一个是
?(因为 是它们确定字母的交集,之外的位至少一个是?)
所以确实能匹配。
因此,对于每个 ,将 的字符串按 上的字母编码分组,同一组内的字符串两两可匹配。
避免重复计数
同一个字符串对 可能被多个 统计到。
我们需要保证每个字符串对只被计算一次。注意到:如果 和 能匹配,那么它们的所有公共确定字母位置集合 上字母相同。
对于 ,它们会被分到同一组。
对于 ,它们也会被分到同一组。
所以会被多次统计。要唯一确定,我们应取 ,即最大公共确定字母集。
如何保证只按这个 统计?
利用容斥原理
设 表示在 上字母编码相同的字符串对数(要求 且 )。
这个 会重复计数那些在更大 上也相同的对。设 表示恰好在 上字母编码相同(且不在更大的公共确定字母集上相同)的对数。
那么: [ f[mask] = \sum_{mask' \supseteq mask} g[mask'] ] 由 Möbius 反演(在高维上是容斥): [ g[mask] = f[mask] - \sum_{mask' \supset mask} g[mask'] ] 我们可以按 从大到小(按位数从多到少)计算 。
最终答案是: [ ans = \sum_{mask} g[mask] ]
计算
对于每个 ,收集所有 的字符串,将它们按在 上的字母编码分类。
设某类有 个字符串,则对 的贡献为 。
算法总流程
- 预处理每个字符串 的 (确定字母位置集合),以及它在 上的字母编码 (可哈希)。
- 枚举所有 ():
- 遍历所有字符串 ,如果 ,则取出 在 上的字母编码 (根据 提取对应位置字母并哈希)。
- 用哈希表统计每个 的出现次数 。
- 。
- 从大到小枚举 (按二进制中 1 的个数从多到少):
- 枚举所有 (可通过枚举超集实现),。
- 答案 。
复杂度
,所以 。
枚举 :
对每个 遍历所有字符串 ,并提取编码(),总 $O(2^M \cdot N \cdot M) \approx 64 \times 5\times 10^4 \times 6 \approx 2\times 10^7$,可行。
哈希表操作总体也是这个量级。
总结
本题利用 很小的条件,通过状态压缩和容斥原理,将字符串匹配问题转化为集合分类计数问题。
关键点:- 两个字符串能匹配当且仅当在它们都确定字母的位置上字母相同。
- 枚举公共确定字母集合 ,统计在该 上字母相同的字符串对数。
- 用容斥去掉重复计数,得到恰好以 为最大公共确定字母集的对数。
- 求和即得答案。
时间复杂度 ,在给定范围内可行。
- 1
信息
- ID
- 5738
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者