版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/88696664
题目:BZOJ3238.
题目大意:给定一个字符串
,求:
其中
表示
以第
个字符为开头的后缀,
表示
的长度,
表示
的最长公共前缀长度.
.
考虑两个后缀的LCP是什么,其实就是两个后缀各自在后缀树上表示的点的LCA.
考虑用构造原串的反串的SAM来得到后缀树,那么两个节点的LCP长度就是它们LCA的 值,然后考虑如何在后缀树上操作.
考虑将原式转变为:
所以我们只要dfs一遍整棵后缀树,计算每一个节点是多少点对的LCA即可,这可以用一个简单的树形DP实现.
时间复杂度 .
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=500000,C=26;
struct automaton{
int s[C],len,par;
}tr[N*2+9];
int cn,last,rght[N*2+9];
void Build_sam(){cn=last=1;}
void extend(int x){
int np=++cn,p=last;
tr[np].len=tr[p].len+1;rght[np]=1;
last=np;
while (p&&!tr[p].s[x]) tr[p].s[x]=np,p=tr[p].par;
if (!p) tr[np].par=1;
else{
int q=tr[p].s[x];
if (tr[p].len+1==tr[q].len) tr[np].par=q;
else{
tr[++cn]=tr[q];tr[cn].len=tr[p].len+1;
tr[np].par=tr[q].par=cn;
while (p&&tr[p].s[x]==q) tr[p].s[x]=cn,p=tr[p].par;
}
}
}
struct side{
int y,next;
}e[N*2+9];
int lin[N*2+9],top;
void ins(int x,int y){
e[++top].y=y;
e[top].next=lin[x];
lin[x]=top;
}
void Build_parent(){
for (int i=2;i<=cn;++i)
ins(tr[i].par,i);
}
LL ans;
void dfs_rght(int k){
for (int i=lin[k];i;i=e[i].next){
dfs_rght(e[i].y);
ans-=2LL*tr[k].len*rght[k]*rght[e[i].y];
rght[k]+=rght[e[i].y];
}
}
char s[N+9];
int n;
Abigail into(){
scanf("%s",s+1);
n=strlen(s+1);
}
Abigail work(){
Build_sam();
for (int i=n;i>=1;--i)
extend(s[i]-'a');
Build_parent();
for (int i=1;i<=n;++i)
ans+=(LL)i*(i-1)/2*3;
dfs_rght(1);
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}