字符串自我治疗
我字符串啥都不会,只会\(O(n^2)\)匹配,\(O(n^3)\)暴力统计答案,一开始认为考字符串就直接摆烂了,但是发现这种心理是不对的,学习,是为自己学的。
\(SAM\)
void Ins(int c)
{
int p=last;
last=++tot;
int now=tot;
len[now]=len[p]+1;
for(;p&&!tr[p][c];p=fa[p]) tr[p][c]=now;
if(!p) fa[now]=1;
else
{
int q=tr[p][c];
if(len[q]==len[p]+1) fa[now]=q;
else
{
int spilt=++tot;
for(int i=0;i<=25;i++) tr[spilt][i]=tr[q][i];
fa[spilt]=fa[q];
len[spilt]=len[p]+1;
fa[q]=fa[now]=spilt;
for(;p&&tr[p][c]==q;p=fa[p]) tr[p][c]=spilt;
}
}
}
不同子串个数
每次统计答案时候直接\(res+=len[now]-len[fa[now]]\)即可
两个字符串的最长公共子串
对第一个串构建\(SAM\),第二个串去匹配,类似于\(AC\)自动机匹配过程
匹配的情况分三种,有转移边,直接\(+1\)
没有的话,往上跳,向当于缩小串长到一个尽可能满足的位置,然后继续匹配
void sol()
{
int p=1,ln=0;
for(int i=1;s2[i];i++)
{
int c=s2[i]-'a';
if(tr[p][c]) ln++,p=tr[p][c];
else
{
for(;p&&!tr[p][c];p=fa[p]);
if(p) ln=len[p]+1,p=tr[p][c];
else p=1,ln=0;
}
Ans=max(Ans,ln);
}
cout<<Ans<<"\n";
}
动态维护不同子串
其实和第一个一样,实时输出即可
出现k次字符串
直接建立后缀树求子树和统计即可
void dfs(int now)
{
for(int i=0;i<rd[now].size();i++)
{
int y=rd[now][i];
dfs(y);
cnt[now]+=cnt[y];
}
}