字符串

一些模版

字符串哈希

核心:将一个字符串映射为一个数值。

写法

\(O(n)\)预处理字符串所有前缀哈希值,\(O(1)\)访问任意子串的哈希值。

进制数取\(k=131\)或者是\(k=13331\)

模数取\(998244353\)或者直接用unsigned long long 自然溢出。

  • 求整串的哈希值
LL calc(char s[],int len){
    LL res=0ll;
    for(int i=1;i<=len;i++)
        res=add(mul(res,k),s[i]);
    return res;
}
  • 拼接/删除串后的哈希值

\(H(S+c)=(H(S)*k+c)%p\)

  • 提取子串哈希值

\(H(S_{lr})=(H(S_r)-H(S_{l-1})\times k^{r-l+1}+p)\%p\)

存储方式

unordered_map存\(O(1)\)

应用

1.判断一个字符串是否出现过

2.判断字符串是否相等

3.找某两个位置开始的最长公共前缀

二分位置+哈希判断

\(O(logn)\)

4.判断两个串字符串大小

找最长公共前缀,判断下一位大小。

5.允许\(k\)次失配的字符串匹配

哈希加二分。

计算出字符串的哈希值

枚举所有可能匹配的子串。

二分第一次失配的位置,删去失配位置之前的串,进行类似操作。

\(O(n+klog_2m)\)

6.判断\(S_i\)是否是\(S_j\)的循环节。

O(1)

\(hash(s_j)*k^{len_i}+hash(s_i)=hash(s_i)*p^{len_j}+hash(s_j)\)

最长公共子字符串

计算字符串,用map存一下。

确定字符串中不同子字符串的数量

枚举所有子串,查询hash值,去重。

题目

优秀的拆分

95分

\(pre[i],suf[i]\)表示从\(i\)开始,往左边以及往右边凑出形如AA串的方案数。

答案即为\(\sum_{i=1}^{n}pre[i]\times suf[i+1]\)

怎么求方案数,\(O(n^2)\)暴力枚举所有\([l,r]\)\(O(1)\)哈希判断是不是AA串。

Compress Words

维护\(A,S[i]\)的哈希值,从小到大枚举\(S[i]\)的前缀,查看A串长度相同的后缀和该前缀是否一样。哈希\(O(1)\)判断。每次查询完\(S[i]\)后,插入这一串的哈希值。

最差进行1e6次枚举。

KMP字符串匹配

给出两个串A,B。求B字符串在A字符串中出现的位置。

\(O(n+m)\)

核心:利用匹配失败后的信息,尽量减少模式串与主串的匹配次数。

写法

进行模式串的自我匹配

nxt[i]:b[1~i]这个子串中,最长的前缀等于后缀的长度。

模式串与字符串匹配

f[i]:是b字符串前缀且最长的a[1~i]的后缀的长度。

用法

1.模式串在主串中出现的次数

2.求一个串的循环节,(可以匹配出去)。

长度为\(n\)的字符串的最短循环节是\(n-nxt[n]\)

\(n\%(n-nxt[n]==0)\)时,字符串是一个循环字符串。最长循环次数为\(\frac{n}{n-nxt[n]}\)

题目

基因改造

神奇的一道题。

考虑两个串什么时候是匹配的。当两个字符串拥有相同的形式时,这个条件可以转化为一个字符和上一个相同字符的距离相等时。

所以可以把字符串中的每一个都改为这样的距离,然后进行kmp匹配。

可以观察题目的性质转化匹配条件,然后用kmp就可以求出字符串中所有满足条件的子串以及出现的位置。

字符串大师

最短循环节的长度已经给出。那么\(i-per[i]=nxt[i]\)

跑kmp构造就可以了。

posted @ 2021-11-13 21:29  RapunzelOnly  阅读(131)  评论(0)    收藏  举报