题意:
给定字符串S,求
∑1≤i<j≤nlen(suffix(i))+len(suffix(j))−lcp(suffix(i),suffix(j))
题解:后缀数组
首先前面的一部分,每个后缀被枚举的次数为
n−1
,所以前部分的贡献为
(n−1)⋅n(n+1)2
。
对于后面一部分,考虑每一个height的贡献,这个height产生贡献时,当且仅当此height枚举两串排名之间的height最小值,所以可以用单调队列维护。
有一个比较麻烦的情况是前后有相同的值,一起计算就会重复。
如:{2,2,2,2,}。直接计算就是1*3+2*2+3*1=10,实际上只会枚举6次。
此时考虑左边相同的都要计算,右边不计算相同的。那么贡献就变成了1*1+2*1+3*1=6。(反过来只计算右边的也可以)。
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int Maxn=5e5+50;
int n,m,INF,a[Maxn],b[Maxn],*rk=a,*sa2=b,h[Maxn],sa[Maxn],c[Maxn],bg[Maxn],ed[Maxn];
char ch[Maxn];
pii st[Maxn];
inline void Rsort()
{
for(int i=1;i<=m;i++)c[i]=0;
for(int i=1;i<=n;i++)c[rk[i]]++;
for(int i=1;i<=m;i++)c[i]+=c[i-1];
for(int i=n;i>=1;i--)sa[c[rk[sa2[i]]]--]=sa2[i];
}
inline void getsa()
{
for(int i=1;i<=n;i++)rk[i]=ch[i],sa2[i]=i;
m=123;Rsort();
for(int w=1,p=0;p<n;m=p,w<<=1)
{
p=0;
for(int i=n-w+1;i<=n;i++)sa2[++p]=i;
for(int i=1;i<=n;i++)if(sa[i]>w)sa2[++p]=sa[i]-w;
Rsort();swap(rk,sa2);rk[sa[1]]=p=1;
for(int i=2;i<=n;i++)rk[sa[i]]=(sa2[sa[i]]!=sa2[sa[i-1]]||sa2[sa[i]+w]!=sa2[sa[i-1]+w])?(++p):p;
}
for(int k=0,i=1,j;i<=n;h[rk[i++]]=k)
for(k?(k--):k,j=sa[rk[i]-1];ch[i+k]==ch[j+k];k++);
}
int main()
{
scanf("%s",ch+1);
INF=n=strlen(ch+1);getsa();
long long ans=1ll*(n-1)*(n)*(n+1)/2;
for(int i=1,nowpos=0;i<=n;i++)
{
int cnt=0;
while(nowpos&&st[nowpos].first>=h[i])cnt+=st[nowpos--].second;
bg[i]=cnt;
if(cnt)st[++nowpos]=make_pair(h[i],cnt);
st[++nowpos]=make_pair(INF,1);
}
for(int i=n,nowpos=0;i>=1;i--)
{
int cnt=0;
while(nowpos&&st[nowpos].first>h[i])cnt+=st[nowpos--].second;
ed[i]=++cnt;
st[++nowpos]=make_pair(h[i],cnt);
}
for(int i=1;i<=n;i++)ans-=2ll*h[i]*bg[i]*ed[i];
printf("%lld",ans);
}