一看是字符串题,就想一想怎么在后缀自动机上搞
有一个跟BZOJ3238 差异差不多的思路,建出原串反串的后缀自动机,那么每个子串的lcp就是对应节点的lca,那么lcp出现次数就是这个节点的right集合,拷了拷之前的代码,改一改就过了……
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#define N 500010<<1
using namespace std;
typedef long long ll;
struct SAM_{
int next[N][26],fail[N],stp[N],p,cnt,t[N],r[N];
ll f[N],w[N];
SAM_(){p=cnt=1;}
void clear(){
p=cnt=1;
memset(next,0,sizeof(next));
memset(fail,0,sizeof(fail));
memset(stp,0,sizeof(stp));
memset(t,0,sizeof(t));
memset(r,0,sizeof(r));
memset(f,0,sizeof(f));
memset(w,0,sizeof(w));
}
void Extend(int x){
x-='a';
int np=++cnt;stp[np]=stp[p]+1;w[np]=f[np]=1;
while(p&&!next[p][x]) next[p][x]=np,p=fail[p];
if(!p) fail[np]=1;
else{
int q=next[p][x];
if(stp[q]==stp[p]+1) fail[np]=q;
else{
int nq=++cnt;stp[nq]=stp[p]+1;
memcpy(next[nq],next[q],sizeof(next[q]));
fail[nq]=fail[q];
fail[q]=fail[np]=nq;
while(p&&next[p][x]==q) next[p][x]=nq,p=fail[p];
}
}
p=np;
}
void Samort(){
int i;
for(i=0;i<=cnt;i++) t[i]=0;
for(i=1;i<=cnt;i++) t[stp[i]]++;
for(i=1;i<=cnt;i++) t[i]+=t[i-1];
for(i=1;i<=cnt;i++) r[t[stp[i]]--]=i;
}
void Solve(int n){
for(int i=cnt;i;i--)f[fail[r[i]]]+=f[r[i]];
ll Ans=0;
for(int i=2;i<=cnt;i++)
Ans+=1LL*(stp[i]-stp[fail[i]])*f[i]*f[i];
printf("%lld\n",Ans);
}
}SAM;
char A[N];
int n;
int main(){
int t;
scanf("%d",&t);
while(t--){
SAM.clear();
scanf("%s",A+1);n=strlen(A+1);
for(int i=n;i;i--)
SAM.Extend(A[i]);
SAM.Samort();
SAM.Solve(n);
}
}