关于字符串的一些乱搞

一些乱搞

众所周知,实际上大部分字符串算法都可以通过二分加哈希来替代,比如“马拉车”。
不止是这样,有些时候传统算法做起来比较困难,反而一些乱搞更加高效。

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)' 可以快速遍历成功匹配的位置。

例题

  1. CF941D
  2. CF963D
posted @ 2025-05-09 01:15  Hanggoash  阅读(9)  评论(0)    收藏  举报
动态线条
动态线条end