luogu P4070 [SDOI2016]生成魔咒

首先有两个结论:
1.后缀自动机具有最简性,即每种不同的子串只会在sam上体现一次,体现形式是sam上一条由root出发的路径。
2.一个字符串不同子串的个数等于所有关键节点的max(x)-min(x)+1。证明就是考虑后缀自动机的最简性。

然后,这就是个水题了。
每次插入一个字符后,更新答案即可。

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<map>
#include<cstdlib>
#include<algorithm>
#define N 330000
#define L 300000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline int read()
{
	char ch=0;
	int x=0,flag=1;
	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*flag;
}
char ch[N];
bool flag[N];
int root=1,size=1,last=1,id[N];
struct node{int len,link;map<int,int>nxt;}s[N];
void insert(int k)
{
	int cur=++size,p=last;
	s[cur].len=s[p].len+1;
	while(p&&!s[p].nxt[k])
	{
		s[p].nxt[k]=cur;
		p=s[p].link;
	}
	last=cur;
	if(!p){s[cur].link=root;return;}
	int q=s[p].nxt[k];
	if(s[q].len==s[p].len+1)s[cur].link=q;
	else
	{
		int clone=++size;
		s[clone]=s[q];
		s[clone].len=s[p].len+1;
		while(p&&s[p].nxt[k]==q)
		{
			s[p].nxt[k]=clone;
			p=s[p].link;
		}
		s[q].link=s[cur].link=clone;
	}
}
int main()
{
	ll ans=0;
	int n=read();
	for(int i=1;i<=n;i++)
	{
		int x=read();
		insert(x);
		ans+=s[last].len-s[s[last].link].len;
		printf("%lld
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Creed-qwq/p/10159601.html