BZOJ3238: [Ahoi2013]差异
题解:
后缀自动机用起来非常好用。。
首先根到每个特殊点就是原串的前缀(size=1)
那么我们会发现在parent树上 right集合不断变成后缀
那么他们的lca就是他们的最长公共后缀
于是问题变成了树上给n个点求len[lca]的和
显然dfs一遍就可以完成了
后缀数组做这题也是比较简单的
枚举最小值单调栈维护就可以了
代码:
#include <bits/stdc++.h> #define ll long long #define rint register int #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) using namespace std; const int N=1.1e6; char s[N]; int size[N],len[N],ch[N][26],sum[N]; int lst=1,node=1,t[N],a[N],w[N],fa[N],T,k; void extend(int c) { int f=lst,p=++node; lst=p; len[p]=len[f]+1; w[p]=size[p]=1; while (f&&!ch[f][c]) ch[f][c]=p,f=fa[f]; if (!f) { fa[p]=1; return;}; int x=ch[f][c],y=++node; if (len[f]+1==len[x]) {fa[p]=x; node--;return;}; len[y]=len[f]+1; fa[y]=fa[x]; fa[x]=fa[p]=y; memcpy(ch[y],ch[x],sizeof(ch[x])); while (f&&ch[f][c]==x) ch[f][c]=y,f=fa[f]; } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); cin>>s; int n=strlen(s); int l=strlen(s); dep(i,l,1) extend(s[i-1]-'a'); rep(i,1,node) t[len[i]]++; rep(i,1,node) t[i]+=t[i-1]; rep(i,1,node) a[t[len[i]]--]=i; ll ans=0; rep(i,1,n) ans+=1ll*i*(n-1); dep(y,node,1) { int i=a[y]; size[fa[i]]+=size[i]; ans-=2ll*w[fa[i]]*size[i]*len[fa[i]]; w[fa[i]]+=size[i]; } printf("%lld",ans); return 0; }