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;
}