描述见原题。
分析
首先可以分出一堆常数为:(N-1)*(N+1)*N/2,可以自行推。
剩下的就是减去两两后缀之间LCP的2倍了。我们知道对于两个后缀i、j,它们的LCP取的是Height[i+1]~Height[j]之间的最小值,那么问题就是对于所有的区间,取一个最小值。
转化一下问题,转化为求每个Height可以在多少区间里做最小值,直接得解。一个想法是维护两个数组,分别记录Height[i]向左和向右遇到的第一个小于等于它的Height下标。
另一个很巧妙的方法是维护一个单调栈,使得底部的Height总小于等于顶部Height。设Height[p]是第一个小于等于Height[i]的,那么设,且。由于栈是单调的,对于后进来的Height的位置,之前的Height在这之间也可以成为最小值。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long LL;
const int MAXN=500005;
char s[MAXN];
int a[MAXN];
int RANK[MAXN];
int cnt[MAXN];
int tmp[MAXN];
int SA[MAXN];
int height[MAXN];
int N,M;
LL f[MAXN];
struct data{int id,val;}stk[MAXN];
void init()
{
scanf("%s",s);
N=strlen(s);
for(int i=0;i<N;i++) a[i+1]=s[i];
}
void Rsort()
{
for(int i=0;i<=M;i++) cnt[i]=0;
for(int i=1;i<=N;i++) cnt[RANK[tmp[i]]]++;
for(int i=1;i<=M;i++) cnt[i]+=cnt[i-1];
for(int i=N;i>=1;i--) SA[cnt[RANK[tmp[i]]]--]=tmp[i];
}
int cmp(int *f,int x,int y,int w) {return f[x]==f[y]&&f[x+w]==f[y+w];}
void suffix()
{
for(int i=1;i<=N;i++) RANK[i]=a[i],tmp[i]=i;
M=200,Rsort();
for(int w=1, p=1, i; p<N; w+=w, M=p)
{
for(p=0, i=N-w+1; i<=N; i++) tmp[++p]=i;
for(i=1; i<=N; i++) if(SA[i]>w) tmp[++p]=SA[i]-w;
Rsort();swap(RANK,tmp);RANK[SA[1]]=p=1;
for(i=2; i<=N; i++) RANK[SA[i]]= cmp(tmp,SA[i],SA[i-1],w)? p: ++p;
}
int j,k=0;
for(int i=1; i<=N; height[RANK[i++]]=k)
for(k= k? k-1: k, j=SA[RANK[i]-1]; a[i+k]== a[j+k]; k++);
}
void solve()
{
int pos=0,top=0;
LL del=0;
for(int i=1;i<=N;i++)
{
int p=pos;
while(top&&stk[top].val>height[i]) top--;
if(top) p=stk[top].id;
f[i]=f[p]+(LL)(i-p)*height[i];
del+=f[i];
if(!height[i]) pos=i;
stk[++top]=(data){i,height[i]};
}
cout<<(LL)(N-1)*(N+1)*N/2-del*2;
}
int main()
{
init();
suffix();
solve();
return 0;
}