bzoj3238 [Ahoi2013]差异 后缀自动机

题意:给出一个串,求其中任意两个字串的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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值