字符串
一些模版
字符串哈希
核心:将一个字符串映射为一个数值。
写法
\(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串。
维护\(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构造就可以了。

浙公网安备 33010602011771号