字符串自我治疗

字符串自我治疗

我字符串啥都不会,只会\(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];
	 }
}
posted @ 2022-06-10 21:39  Authentic_k  阅读(66)  评论(0编辑  收藏  举报