洛谷 P2408 不同子串个数【SAM】

传送门

题解

后缀自动机板子题,直接统计 DAG 的路径数量即可,或者根据 \(len\) 数组的性质,即 \(x\) 节点产生的未出现的子串数量为 \(len[x]-len[fa[x]]\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int n;
char s[N];
LL ans;
struct SuffixAutoMachine{
	char *s;
	int tot,last,ch[N*2][26],fa[N*2],len[N*2];
	LL f[N*2];
	int newnode(int id){tot++;memcpy(ch[tot],ch[id],sizeof(ch[tot]));fa[tot]=fa[id];len[tot]=len[id];return tot;}
	void insert(int c){
		int p=last,np=last=newnode(0);
		len[np]=len[p]+1;
		for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
		if(!p) {fa[np]=1;return;}
		int q=ch[p][c];
		if(len[q]==len[p]+1) {fa[np]=q;return;}
		int nq=newnode(q);len[nq]=len[p]+1;
		fa[q]=fa[np]=nq;
		for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
	}
	LL dfs(int u){
		if(f[u]) return f[u];
		for(int i=0;i<26;i++) if(ch[u][i]) f[u]+=dfs(ch[u][i])+1;
		return f[u];
	}
	void init(char *_s){
		memset(f,0,sizeof(f));
		s=_s;last=newnode(0);
		for(int i=1;i<=n;i++) insert(s[i]-'a');
		ans=dfs(1);
	}
}sam;

int main(){
	scanf("%d",&n);
	scanf("%s",s+1);
	sam.init(s);
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-04-09 23:43  BakaCirno  阅读(121)  评论(0编辑  收藏  举报