您的位置:首页 > 其它

[BZOJ3238][Ahoi2013][后缀自动机][树形DP]差异

2017-01-31 11:13 483 查看

题意



∑len(Ti)+∑len(Tj)可以O(1)计算出来。

主要就是求lcp(Ti,Tj)

将字符串反过来,建立后缀自动机,parent树就是原串的后缀树,lcp就是对应节点的lca,树形DP。



这幅图来自一篇不错的后缀自动机讲解

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#define N 500010<<1

using namespace std;

typedef long long ll;

struct SAM_{
int next
[26],fail
,stp
,p,cnt,t
,r
;
ll f
,w
;
SAM_(){p=cnt=1;}
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 Ans1=1ll*n*(n+1)/2*(n-1),Ans2=0;
for(int i=1;i<=cnt;i++){
Ans2+=1ll*w[fail[i]]*stp[fail[i]]*f[i];
w[fail[i]]+=f[i];
}
printf("%lld\n",Ans1-Ans2*2);
}
}SAM;

char A
;
int n;

int main(){
scanf("%s",A+1);n=strlen(A+1);
for(int i=n;i;i--)
SAM.Extend(A[i]);
SAM.Samort();
SAM.Solve(n);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: