P4248
题目描述
题解
考虑维护两部分答案。
第一部分是
∑
1
≤
i
<
j
≤
n
l
e
n
[
T
i
]
+
l
e
n
[
T
j
]
=
n
(
n
−
1
)
(
n
+
1
)
/
2
\sum_{1\le i<j\le n}len[T_i]+len[T_j]=n(n-1)(n+1)/2
∑1≤i<j≤nlen[Ti]+len[Tj]=n(n−1)(n+1)/2
第二部分是
∑
1
≤
i
<
j
≤
n
2
∗
l
c
p
(
T
i
,
T
j
)
\sum_{1\le i<j\le n}2*lcp(T_i,T_j)
∑1≤i<j≤n2∗lcp(Ti,Tj),即求每个区间的
h
e
i
g
h
t
height
height最小值之和,单调栈即可解决
代码
#include<bits/stdc++.h>
#define M 500009
#define int long long
using namespace std;
int m,n,rk[M],tp[M],sa[M],tax[M],height[M],ans,q[M],num[M];
char s[M];
int getans(){
int l=1,r=0,cnt=n;
for(int i=1;i<=n;i++) num[i]=(n-1)*i;
ans-=num[cnt--];
height[n+1]=0;//注意加一个0,清空单调栈
for(int i=1;i<=n+1;i++){
while(l<=r&&height[i]<=height[q[r]]){
ans+=2*((i-q[r])*(q[r]-q[r-1]))*height[q[r]];
while(ans>0) ans-=num[cnt--];
r--;
}q[++r]=i;
}while(cnt) ans-=num[cnt--];
return -ans;
}
void getheight(){
int j=0,k=0;
for(int i=1;i<=n;i++){
if(k) k--;
int j=sa[rk[i]-1];
while(s[j+k]==s[i+k]) k++;
height[rk[i]]=k;
}
}
void Qsort(){
for(int i=0;i<=m;i++) tax[i]=0;
for(int i=1;i<=n;i++) tax[rk[i]]++;
for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(int i=n;i>=1;i--) sa[tax[rk[tp[i]]]--]=tp[i];
}
void Suffix(){
for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
m=127;Qsort();
for(int p=0,w=1;p<n;m=p,w<<=1){
p=0;
for(int i=1;i<=w;i++) tp[++p]=n-w+i;
for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
Qsort();std::swap(tp,rk);
rk[sa[1]]=p=1;
for(int i=2;i<=n;i++)
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
}getheight();
//for(int i=1;i<=n;i++) printf("%lld\n",height[i]);
}
signed main(){
scanf("%s",s+1);
n=strlen(s+1);Suffix();
printf("%lld\n",getans());
return 0;
}