luogu P3804 【模板】后缀自动机 (SAM)

每个子串的出现次数就是其后缀自动机上所在节点的endpos等价类集合的大小。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N=3000009;
char s[N];
int n;
struct Suffix_DFA
{
	int Siz,last;
	struct Dot
	{
		int len,link,ch[30],end;
	}sam[N];
	int head[N],cnt,Ans;
	struct Edge
	{
		int nxt,to;
	}g[N*2];
	
	void add(int from,int to)
	{
		g[++cnt].nxt=head[from];
		g[cnt].to=to;
		head[from]=cnt;
	}
	
	void init()
	{
		sam[0].link=-1;
	}
	
	void SAM_Extend(int k)
	{
		int cur=++Siz;
		sam[cur].len=sam[last].len+1,sam[cur].end=1;
		int p=last;
		while(p!=-1&&!sam[p].ch[k])
			sam[p].ch[k]=cur,
			p=sam[p].link;
		if(p==-1)
			sam[cur].link=0;
		else
		{
			int q=sam[p].ch[k];
			if(sam[q].len==sam[p].len+1)
				sam[cur].link=q;
			else
			{
				int clone=++Siz;
				sam[clone].len=sam[p].len+1;
				sam[clone].link=sam[q].link;
				for (int i=1;i<=26;i++)
					sam[clone].ch[i]=sam[q].ch[i];
				while(p!=-1&&sam[p].ch[k]==q)
					sam[p].ch[k]=clone,
					p=sam[p].link;
				sam[q].link=sam[cur].link=clone;
			}
		}
		last=cur;
	}
	
	void build()
	{
		for (int i=1;i<=Siz;i++)
			add(sam[i].link,i);
	}
	
	void dfs(int x)
	{
		for (int i=head[x];i;i=g[i].nxt)
		{
			int v=g[i].to;
			dfs(v);
			sam[x].end+=sam[v].end;
		}
		Ans=max(Ans,(sam[x].end==1?0:sam[x].end)*sam[x].len);
	}
	
	int Get_Ans()
	{
		build(),dfs(0);
		return Ans;
	}
}A;

void init()
{
	scanf("%s",s+1);
}

void work()
{
	n=strlen(s+1),A.init();
	for (int i=1;i<=n;i++)
		A.SAM_Extend(s[i]-'a'+1);
	printf("%d
",A.Get_Ans());
}

int main()
{
	init();
	work();
	return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!
原文地址:https://www.cnblogs.com/With-penguin/p/13341880.html