【后缀自动机模板 | 洛谷P3804】后缀自动机 SAM

模板题
本文只是放上后缀自动机的模板,并不会对后缀自动机的原理进行讲解。

首先放上模板:

#include 
#define sc(n) scanf("%d",&n)
#define pt(n) printf("%d\n",n)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define vi vector
#define vl vector
#define pb push_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e6+7;
struct node
{
	int ch[26];
	int len,fa;
}point[maxn<<1];
int las = 1,tot = 1,ans;
inline void add(char c)
{
	int p = las;
	int np = las = ++tot;
	point[np].len = point[p].len+1;
	for(;p && !point[p].ch[c];p=point[p].fa) point[p].ch[c] = np;
	if(!p) point[np].fa = 1;
	else
	{
		int q = point[p].ch[c];
		if(point[q].len==point[p].len+1) point[np].fa = q;
		else
		{
			int nq = ++tot;
			point[nq] = point[q];
			point[nq].len = point[p].len+1;
			point[q].fa = point[np].fa = nq;
			for(;p && point[p].ch[c]==q;p=point[p].fa) point[p].ch[c] = nq;
		}
	}
}
char s[maxn];
int main()
{
	scanf("%s",s);
	int l = strlen(s);
	for(int i=0;i<l;i++) add(s[i]-'a');
	return 0;
}

多么美妙的模板

然后我们来分析一下本文的题目:

请你求出字符串的所有出现次数不为1的子串的出现次数乘上该子串长度的最大值。

那么怎么解决呢?

首先,有一个结论:后缀自动机中每个endpos集合的大小即该子串的出现次数。
而这个集合的大小是parent tree上儿子的大小。
如果我们设cnt[s]表示s的子树的大小,那么结果显然就是max(cnt[s]*point[s].len)
所以我们只需要在构造SAM的时候给终止节点标记为1,并从fa[i]向i连边跑dfs统计子树的大小就可以了。
代码如下:
注:吸氧才可过…

#include 
#define sc(n) scanf("%d",&n)
#define pt(n) printf("%d\n",n)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define vi vector
#define vl vector
#define pb push_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e6+7;
struct node
{
	int ch[26];
	int len,fa;
}point[maxn<<1];
int las = 1,tot = 1,ans;
int cnt[maxn<<1]; 
vector<int> G[maxn<<1];
inline void add(char c)
{
	int p = las;
	int np = las = ++tot;
	cnt[tot] = 1;
	point[np].len = point[p].len+1;
	for(;p && !point[p].ch[c];p=point[p].fa) point[p].ch[c] = np;
	if(!p) point[np].fa = 1;
	else
	{
		int q = point[p].ch[c];
		if(point[q].len==point[p].len+1) point[np].fa = q;
		else
		{
			int nq = ++tot;
			point[nq] = point[q];
			point[nq].len = point[p].len+1;
			point[q].fa = point[np].fa = nq;
			for(;p && point[p].ch[c]==q;p=point[p].fa) point[p].ch[c] = nq;
		}
	}
}
void dfs(int s)
{
	for(int i=0;i<G[s].size();i++)
	{
		dfs(G[s][i]);
		cnt[s] += cnt[G[s][i]];
	}
	if(cnt[s]>1) ans = max(ans,cnt[s]*point[s].len); 
}
char s[maxn];
int main()
{
	scanf("%s",s);
	int l = strlen(s);
	for(int i=0;i<l;i++) add(s[i]-'a');
	for(int i=2;i<=tot;i++) G[point[i].fa].pb(i);
	dfs(1);
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(算法模板)