Luogu4248 [AHOI2013]差异

https://www.luogu.com.cn/problem/P4248

后缀自动机

观察原式,类似树上两点间距离

显然,这棵树是\(Parent\)

那么,跑一遍\(dfs\)即可

对于边权,\(lcp\)最长公共前缀,而\(len\)表示同一\(endpos\)集合中最长子串长度,因此能够表示\(lcp\),同时\(len\)也表示了后缀长度

\(C++ Code:\)

#include<bits/stdc++.h>
#define N 1000005
#define M 1500005
using namespace std;
int tot,head[M],d[M],d2[M],nxt[M],sz[M];
int t[N][26],pre[N],len[N];
int n,cnt=1,last=1;
long long ans=0;
char s[N],s1[N];
void ins(int c)
{
	int p,q;
	int np=++cnt;
	sz[np]=1;
	len[np]=len[last]+1;
	for (p=last;p&&!t[p][c];p=pre[p])
		t[p][c]=np;
	if (!p)
		pre[np]=1; else
		{
			q=t[p][c];
			if (len[p]+1==len[q])
				pre[np]=q; else
				{
					int g=++cnt;
					len[g]=len[p]+1;
					for (int i=0;i<26;i++)
						t[g][i]=t[q][i];
					pre[g]=pre[q];
					for (;p&&t[p][c]==q;p=pre[p])
						t[p][c]=g;
					pre[q]=pre[np]=g;
				}
		}
	last=np;
}
void add(int x,int y,int z)
{
	tot++;
	d[tot]=y;
	d2[tot]=z;
	nxt[tot]=head[x];
	head[x]=tot;
}
void dfs(int u)
{
	for (int i=head[u];i;i=nxt[i])
	{
		int v=d[i];
		int v2=d2[i];
		dfs(v);
		ans+=(long long)sz[v]*(n-sz[v])*v2;
		sz[u]+=sz[v];
	}
}
int main() 
{
	scanf("%s",s);
	n=strlen(s);
	for (int i=1;i<=n;i++)
		s1[i-1]=s[n-i];
	for (int i=0;i<n;i++)
		ins(s1[i]-'a');
	for (int i=2;i<=cnt;i++)
		add(pre[i],i,len[i]-len[pre[i]]);
	dfs(1);
    cout << ans << endl;
	return 0;
}
posted @ 2020-07-23 15:49  GK0328  阅读(93)  评论(0编辑  收藏  举报