您的位置:首页 > 其它

BZOJ 3238 [Ahoi2013]差异(后缀自动机)

2017-09-14 15:00 507 查看
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=3238

【题目大意】

  给出一个串,设T[i]表示从第i位开始的后缀,
  求sum(len(T[i])+len(T[j])-2*lcp(T[i],T[j]))

【题解】

  根据反串的后缀自动机建立后缀树,  
  则两点的LCA在自动机中的length就是他们的LCP,
  树形DP统计一下即可。

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N=1000010;
struct SAM{
char s
;
int p,q,np,nq,cnt,lst,a
[26],l
,f
,size
,tot;
int Tr(char c){return c-'a';}
SAM(){cnt=0;lst=++cnt;}
void extend(int c){
p=lst;np=lst=++cnt;l[np]=l[p]+1;size[np]=1;
while(!a[p][c]&&p)a[p][c]=np,p=f[p];
if(!p)f[np]=1;
else{
q=a[p][c];
if(l[p]+1==l[q])f[np]=q;
else{
nq=++cnt;l[nq]=l[p]+1;
memcpy(a[nq],a[q],sizeof(a[q]));
f[nq]=f[q]; f[np]=f[q]=nq;
while(a[p][c]==q)a[p][c]=nq,p=f[p];
}
}
}
vector<int> v
;
void BuildTree(){
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=len;i;i--)extend(Tr(s[i]));
for(int i=2;i<=cnt;i++)v[f[i]].push_back(i);
}
long long res;
void Dfs(int x,int fx){
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
Dfs(y,x); size[x]+=size[y];
}l[x]-=l[fx];
res=res-(long long)size[x]*(size[x]-1)*l[x];
}
void ShowResult(){
int len=strlen(s+1);
res=(long long)(len-1)*len*(len+1)/2;
for(int i=0;i<v[1].size();i++)Dfs(v[1][i],1);
printf("%lld\n",res);
}
}sam;
int main(){
sam.BuildTree();
sam.ShowResult();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: