zoukankan      html  css  js  c++  java
  • BZOJ_3238_[Ahoi2013]差异_后缀自动机

    BZOJ_3238_[Ahoi2013]差异_后缀自动机

    Description

    Input

    一行,一个字符串S

    Output

    一行,一个整数,表示所求值

    Sample Input

    cacao

    Sample Output

    54

    HINT

    2<=N<=500000,S由小写英文字母组成


    后缀数组做法:http://www.cnblogs.com/suika/p/8995997.html

    可以发现两个后缀的lcp长度一定是这两个串在后缀树上的lca的深度。

    对后缀树上每个结点维护子树中叶子个数,然后向上走的时候统计一下有多少后缀两两的LCA在当前结点上即可。

    代码:

    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define N 500050
    int ch[N<<1][27],fa[N<<1],dep[N<<1],cnt=1,lst=1,siz[N<<1];
    char s[N];
    int c[N<<1],a[N<<1];
    void insert(int x) {
        int p=lst,np=++cnt,q,nq;
        lst=np; dep[np]=dep[p]+1;
        for(;p&&!ch[p][x];p=fa[p]) ch[p][x]=np;
        if(!p) fa[np]=1;
        else {
            q=ch[p][x];
            if(dep[q]==dep[p]+1) fa[np]=q;
            else {
                fa[nq=++cnt]=fa[q];
                dep[nq]=dep[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[q]=fa[np]=nq;
                for(;p&&ch[p][x]==q;p=fa[p]) ch[p][x]=nq;
            } 
        }
        siz[np]=1;
    }
    int main() {
        scanf("%s",s+1);
        int ln=strlen(s+1);
        int i;
        long long ans=0;
        for(i=ln;i;i--) insert(s[i]-'a');
        for(i=1;i<=cnt;i++) c[dep[i]]++;
        for(i=1;i<=cnt;i++) c[i]+=c[i-1];
        for(i=1;i<=cnt;i++) a[c[dep[i]]--]=i;
        for(i=cnt;i;i--) {
            int p=a[i];
            ans+=1ll*siz[fa[p]]*siz[p]*dep[fa[p]];
            siz[fa[p]]+=siz[p];
        }
        printf("%lld
    ",1ll*ln*(ln-1)*(ln+1)/2-2*ans);
    }
    
  • 相关阅读:
    probuf了解
    rebbitmq-RPC(C#)
    获取指定数量的有序列表
    RPC(Remote Procedure Call Protocol)
    正则表达式(c#)
    02_python函数
    01_python基础
    养生茶
    测试左右移浅淡
    python类的组合
  • 原文地址:https://www.cnblogs.com/suika/p/9033151.html
Copyright © 2011-2022 走看看