bzoj3238 [Ahoi2013]差异 后缀自动机

来源:互联网 发布:胜通软件 编辑:程序博客网 时间:2024/05/16 06:48

题意:给出一个串,求其中任意两个字串的lcp的总和。

我们可以对于这个串建一颗后缀自动机,实际上,他的parent边树就是一颗后缀树,我们在后缀树上统计答案,设f表示right集合的大小,可以理解为后缀树的siz,然后w是f的前缀和。mx按照基数排序,然后扫一遍就可以统计答案了。

 #include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#include<map>using namespace std;int n,m;typedef long long ll;const int N=1e6+5;map<int,int>ch[N];int mx[N],fa[N],f[N],g[N],b[N],c[N];int last,cnt;char s[N];ll ans;inline void ins(int x){    int p,q,np,nq;//p:status  0;    p=last;       //np:newnode    last=np=++cnt;    mx[np]=mx[p]+1;    g[np]=f[np]=1;    for(;!ch[p][x]&&p;p=fa[p])ch[p][x]=np;    if (!p)fa[np]=1;    else    {              //nq:son[q]        q=ch[p][x];//q:laststatus        if (mx[q]==mx[p]+1)fa[np]=q;        else        {            nq=++cnt;            mx[nq]=mx[p]+1;            ch[nq]=ch[q];            fa[nq]=fa[q];            fa[q]=fa[np]=nq;            for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;        }    }}inline ll solve(){    fo(i,1,cnt)b[mx[i]]++;    fo(i,1,n)b[i]+=b[i-1];    fo(i,1,cnt)c[b[mx[i]]--]=i;    fd(i,cnt,1)f[fa[c[i]]]+=f[c[i]];    ll ans=0;    fo(i,1,cnt)    {        ans+=1ll*g[fa[i]]*f[i]*mx[fa[i]];        g[fa[i]]+=f[i];    }    return ans;}int main(){    scanf("%s",s+1);    n=strlen(s+1);    last=cnt=1;    fo(i,1,n)ins(s[i]-'a');    ans=0;    fo(i,1,n)ans+=1ll*i*(n-1);    printf("%lld\n",ans-solve()*2);    return 0;}
0 0
原创粉丝点击