马拉车算法是解决最长回文子串的有力武器
例如 string s=“abadccda”
我们要想求出最长回文子串一般都是暴力,枚举子串的左右端点,一般枚举是o(n2)的复杂度,判断又是又要o(n),也可以用字符串哈希来判断,不过铁定超时.
但马拉车可以坐到o(n)的复杂度,他和kmp的思想很类似就保存前面的信息来利用.
设a[i]表示以i为回文中心的最长回文半径
例如aba(以1为第一个下标) a[2=2;
我们如何求出每一个位置的a[i]呢?
string s=“abadccda”
因为回文子串长度分奇偶,如何处理呢(字母之间插入不相关的字符)
t=#a#b#a#d#c#c#d#a#
这样就都变成了奇回文子串
最终形态
t=!#a#b#a#d#c#c#d#a#$
这样是为了暴力扩展而添加的 (1)
设mid为对称中心,mid之前的a[i]都已经求出来,mr为mid+a[mid]-1,j为i的对称点求a[i]
如果以j为回文子串的子串在以mid为回文子串的子串中,那么以i为回文中心的子串等于以j为回文子串的子串,所以a[i]=a[j]
如果以j为回文子串的子串的左边界大于以mid为回文子串的子串的左边界,那么只能保证以j为回文中心以a[j]-1为回文半径的子串是等于以i为回文中心的子串,因为他们关与mid对称,
之后再对i为回文中心的子串进行暴力扩展,因为这个子串的回文半径还课能更大,(1)处就是为防止暴力扩展越界,
之后更新更大的mr,和mid
最大回文子串长度为最大回文子串半径减一
模板题
#include"bits/stdc++.h"
using namespace std;
char s[22000005],t[32000005];
int a[22000005];
int cnt=0;
int main(){
scanf("%s",s+1);
int n=strlen(s+1);
t[++cnt]='!';
t[++cnt]='#';
for(int i=1;i<=n;i++){
t[++cnt]=s[i];
t[++cnt]='#';
}
t[++cnt]='$';
int mid=0,mr=0,ma=0;
for(int i=2;i<=cnt-1;i++){
if(i<=mr){
a[i]=min(a[2*mid-i],mr-i+1);
}
else a[i]=1;
while(t[i-a[i]]==t[i+a[i]])++a[i];
if(i+a[i]>mr){
mid=i;
mr=i+a[i]-1;
}
ma=max(ma,a[i]);
}
cout<<ma-1;
return 0;
}
字符串哈希比较简单
o(n)的预处理,o(1)的比较字符串
思想就是把一个字符串映射到一个数上,两个字符串比较就为两个数比较
例如
s=“abcde”
我们把s当做一个131进制的数(为什么是131因为会很小概率出现哈希冲突)
s='e’pow(131,0)+'dpow(131,1)+‘c’*pow(131,2)+‘b’*pow(131,3)+‘a’*pow(131,4);
此时s就被映射为一个数,当字符串位数的比较多时,数就很大,我们要对他求余,不过当我们把他设为unsigned long long 时溢出就会自动对pow(2,64)求余,所以我们设为unsigned long long 就行,
hash1[i]表示已i为结束字符串哈希值,base[i]表示pow(131,i);
求[L,R]的字符串哈希值为hash1[R]-hash1[L-1]*base[R-L+1];
有点像前缀和了
模板题
#include"iostream"
#include"string.h"
using namespace std;
typedef unsigned long long ull;
const int base=131;
ull hashh[1000005],p[1000005];
char s[1000005];
int m;
int main(){
scanf("%s",s+1);
p[0]=1;
hashh[0]=0;
int len=strlen(s+1);
for(int i=1;i<=len;i++){
hashh[i]=hashh[i-1]*base+s[i]-'a'+1;
p[i]=p[i-1]*base;
}
cin>>m;
for(int i=1;i<=m;i++){
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
ull a=hashh[r1]-hashh[l1-1]*p[r1-l1+1];
ull b=hashh[r2]-hashh[l2-1]*p[r2-l2+1];
if(a==b){
cout<<"Yes"<<endl;
}
else{
cout<<"No"<<endl;
}
}
return 0;
}