2018.12.15 poj3415 Common Substrings(后缀自动机)

时间:2023-03-08 21:48:55

传送门

后缀自动机基础题。

给两个字符串,让你求长度不小于kkk的公共子串的数量。


这题可以用后缀自动机解决废话

考虑对其中一个字串建出后缀自动机,然后用另一个在上面跑,注意到如果一个状态有贡献的话,从它到根的状态都会有贡献,因此我们给每个节点打一个懒标记最后再统计一次答案即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ri register int
using namespace std;
const int N=2e5+5;
typedef long long ll;
int k,n;
char s[N];
inline int calc(char c){return c>='a'&&c<='z'?c-'a':c-'A'+26;}
struct SAM{
	int tot,rt,last,len[N],link[N],son[N][60],siz[N],lz[N],cnt[N],rk[N];
	inline void init(){
		memset(len,0,sizeof(len)),memset(siz,0,sizeof(siz)),memset(rk,0,sizeof(rk)),memset(son,0,sizeof(son));
		memset(link,0,sizeof(link)),memset(cnt,0,sizeof(cnt)),memset(lz,0,sizeof(lz)),tot=last=rt=1,len[0]=-1;
	}
	inline void expend(int x){
		int p=last,np=++tot;
		siz[last=np]=1,len[np]=len[p]+1;
		while(p&&!son[p][x])son[p][x]=np,p=link[p];
		if(!p){link[np]=rt;return;}
		int q=son[p][x],nq;
		if(len[q]==len[p]+1){link[np]=q;return;}
		len[nq=++tot]=len[p]+1,memcpy(son[nq],son[q],sizeof(son[q])),link[nq]=link[q];
		while(p&&son[p][x]==q)son[p][x]=nq,p=link[p];
		link[q]=link[np]=nq;
	}
	inline void topsort(){
		for(ri i=1;i<=tot;++i)++cnt[len[i]];
		for(ri i=1;i<=last;++i)cnt[i]+=cnt[i-1];
		for(ri i=1;i<=tot;++i)rk[cnt[len[i]]--]=i;
		for(ri i=tot;i;--i)siz[link[rk[i]]]+=siz[rk[i]];
	}
	inline void query(){
		topsort();
		int p=1,nowlen=0;
		ll ans=0;
		for(ri i=1;i<=n;++i){
			int x=calc(s[i]);
			if(son[p][x])p=son[p][x],++nowlen;
			else{
				while(p&&!son[p][x])p=link[p];
				if(!p)p=1,nowlen=0;
				else nowlen=len[p]+1,p=son[p][x];
			}
			if(nowlen>=k){
				ans+=(ll)(nowlen-max(k,len[link[p]]+1)+1)*siz[p];
				if(len[link[p]]>=k)++lz[link[p]];
			}
		}
		for(ri i=tot;i;--i){
			p=rk[i];
			ans+=(ll)lz[p]*siz[p]*(len[p]-max(k,len[link[p]]+1)+1);
			if(len[link[p]]>=k)lz[link[p]]+=lz[p];
		}
		cout<<ans<<'\n';
	}
}sam;
int main(){
	while(scanf("%d",&k),k){
		scanf("%s",s+1),n=strlen(s+1),sam.init();
		for(ri i=1;i<=n;++i)sam.expend(calc(s[i]));
		scanf("%s",s+1),n=strlen(s+1),sam.query();
	}
	return 0;
}