题意
求一个定值 −2× − 2 × 所有后缀的公共前缀
题解
前面那个定值是
考虑把原串翻转过来,那么要求的就是所有前缀公共后缀了
两个前缀的最长公共后缀的答案就是这两个前缀所代表的点在后缀树上 lca l c a 的长度
题目就转化为求树上某一个点是多少点对的 lca l c a 再乘上 len[lca] l e n [ l c a ]
上面这个问题可以直接记录一下子树 sz, s z , 然后 DP D P 求出
#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=5e5+5,M=2*N;
typedef int arr[M];
typedef long long ll;
struct SAM{
int las,T,ch[M][26];arr fa,sz,len;
inline void init(){las=T=1;}
inline void ins(int c){
int p=las,np;fa[las=np=++T]=1,len[T]=len[p]+1;sz[T]=1;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(p){
int q=ch[p][c],nq;
if(len[p]+1==len[q])fa[np]=q;
else{
fa[nq=++T]=fa[q],len[T]=len[p]+1;memcpy(ch[nq],ch[q],4*26);
for(fa[q]=fa[np]=nq;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}arr b,c;ll sum[M];
inline ll calc(){
ll tp=0;
fp(i,1,T)++c[len[i]];
fp(i,1,T)c[i]+=c[i-1];
fp(i,1,T)b[c[len[i]]--]=i;
fd(i,T,1){int u=b[i];
tp+=(ll)sz[fa[u]]*sz[u]*len[fa[u]],sz[fa[u]]+=sz[u];
}
return tp;
}
}p;
int n;char s[N];
int main(){
#ifndef ONLINE_JUDGE
file("s");
#endif
scanf("%s",s);n=strlen(s);p.init();
fp(i,0,n-1)p.ins(s[i]-'a');
printf("%lld\n",(ll)(n-1)*n*(n+1)/2-2*p.calc());
return 0;
}