关于字符串的一些乱搞
一些乱搞
众所周知,实际上大部分字符串算法都可以通过二分加哈希来替代,比如“马拉车”。
不止是这样,有些时候传统算法做起来比较困难,反而一些乱搞更加高效。
Bitset与串的匹配
闲话
仅仅讨论单文本串的情况。
如果模式串给定,求其在文本串中出现的位置,那么就根据模式串集合构建一个 AC自动机。
如果文本串给定,要讨论其本身子串的性质,那么就根据文本串构建一个 SAM。
但是如果文本串给定,有若干个模式串,并且还有若干次修改,这时候想要查询模式串出现的位置,就是一件比较困难的事情。如果要用 AC自动机,显然这里的模式串并不是预先给定的。
bitset的妙用
首先可以明确地一点是,暴力匹配是 \(O(n^2)\) 的,下面就介绍在这基础上,如何用 bitset 来把这个复杂度稍微优化。
操作
假设当前需要查询的串是 \(t\),我们首先开一个文本串 \(s\) 长度的 bitset \(ans\),如果 \(ans_i\) 为 \(1\),就表示 \(s[i:i+|t|-1]\) 是一个合法的匹配,考虑逐步把 \(t\) 中的字符加入,来去除一些不合法的匹配。
在这之前,我们需要根据文本串 \(s\) 的字符集来与预处理出关于文本串本身的 bitset,假设我们只有 \(['a','z']\) 的字符,我们就开 \(26\) 个文本串长度的bitset \(text[26]\),然后对于某个字符 \(c\),\(text[c][i]\) 表示字符 \(c\) 在文本串的 \(i\) 位置处存在与否。
初始,我们将 \(ans\) 全部设置成 \(1\)。
这样,我们每从 \(t\) 中加入一个字符 \(add\) ,就访问对应的 \(text[add]\) ,然后把 \(ans\) 按位与上一个 \(text[add]>>(pos_{add}-1)\),(这里细品,以及注意bitset中的位是从右到左,所以是左移)。
最后所有为 \(1\) 的位置就是成功匹配的位置。
统计
通过 '.count()' 函数可以访问后缀缀和中成功匹配的数量。
通过 '_Find_first()' 和 '_Find_next(iterator)' 可以快速遍历成功匹配的位置。
例题
- CF941D
- CF963D
本文来自博客园,作者:Hanggoash,转载请注明原文链接:https://www.cnblogs.com/Hanggoash/p/18867408

浙公网安备 33010602011771号