题目大意:一个长度为 n 的字符串 S,令
Ti
T
i
表示它从第 i 个字符开始的后缀,求
∑1≤i<j≤nlen(Ti)+len(Tj)−2lcp(Ti,Tj)
∑
1
≤
i
<
j
≤
n
l
e
n
(
T
i
)
+
l
e
n
(
T
j
)
−
2
l
c
p
(
T
i
,
T
j
)
题解:%GXZ大爷
我的收获:2333
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=500005;
const int INF=-1e9;
int n,top,sta[N];
int sa[N],rk[N],rk2[N],height[N],c[N];
int lp[N],rp[N];
char s[N];
int cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
void DA(int n,int m=128)
{
int i,p,k,*x=rk,*y=rk2;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[i]=s[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(k=1,p=1;p<n;k<<=1,m=p){
for(p=0,i=n-k;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y),p=1,x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
}
}
void calh(int n)
{
int i,j,k=0;
for(i=1;i<=n;i++) rk[sa[i]]=i;
for(i=0;i<n;height[rk[i++]]=k)
for(k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
}
void work()
{
long long ans=(long long)n*(n+1)*(n-1)/2;
sta[0]=-INF;top=0;
for(int i=1;i<=n;i++)
{
while(top&&height[sta[top]]>=height[i]) top--;
lp[i]=i-sta[top],sta[++top]=i;
}
sta[0]=n+1,top=0;
for(int i=n;i>=1;i--)
{
while(top&&height[sta[top]]>height[i]) top--;
rp[i]=sta[top]-i,sta[++top]=i;
}
for(int i=1;i<=n;i++) ans-=2ll*lp[i]*rp[i]*height[i];
cout<<ans<<endl;
}
void init()
{
scanf("%s",s);n=strlen(s);s[n]=0;
DA(n+1);calh(n);
}
int main()
{
init();
work();
return 0;
}