zoukankan      html  css  js  c++  java
  • [bzoj3238] [Ahoi2013] 差异

    Description

    给定一个长度为 (n) 的字符串 (S),令 (Ti) 表示它从第 (i) 个字符开始的后缀。求
    (sumlimits_{1 leq i <j leq n} len(Ti)+len(Tj)-2 imes lcp(Ti,Tj))
    其中,(len(a)) 表示字符串 (a) 的长度,(lcp(a,b)) 表示字符串 (a) 和字符串 (b) 的最长公共前缀。

    Input

    一行,一个字符串 (S)

    Output

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

    Sample Input

    cacao

    Sample Output

    54

    HINT

    对于 (100%) 的数据,保证 (2 leq n leq 500000),且均为小写字母。


    想法

    化简一下要求的那个式子

    [egin{equation*} egin{aligned} &sumlimits_{1 leq i <j leq n} len(Ti)+len(Tj)-2 imes lcp(Ti,Tj) \ =&frac{n(n+1)(n-1)}{2} -2 imes sumlimits_{1 leq i <j leq n} lcp(Ti,Tj) end{aligned} end{equation*} ]

    不妨设 (x= sumlimits_{1 leq i <j leq n} lcp(Ti,Tj)) ,我们要求的就是它
    建出后缀自动机,对于其中每个节点,预处理出它可以到的结束节点的个数 (size) ,这个点对 (x) 的贡献就是 (frac{size(size-1)}{2})


    代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    
    const int N = 500005;
    typedef long long ll;
    
    struct node{
        int len,size;
        node *ch[26],*pa;
    }pool[N*2],*root,*last;
    int cnt;
    void insert(int c){
        node *p=last,*cur=&pool[++cnt];
        cur->len=p->len+1;
        for(;p && !p->ch[c];p=p->pa) p->ch[c]=cur;
        if(!p) cur->pa=root;
        else{
            node *q=p->ch[c],*nq;
            if(q->len==p->len+1) cur->pa=q;
            else{
                nq=&pool[++cnt];
                nq->len=p->len+1;
                for(int i=0;i<26;i++) nq->ch[i]=q->ch[i];
                nq->pa=q->pa;
                q->pa=cur->pa=nq;
                for(;p && p->ch[c]==q;p=p->pa) p->ch[c]=nq;
            }
        }
        last=cur;
    }
    
    char s[N];
    int n;
    
    ll ans,del[N*2];
    int vis[N*2];
    void Get_size(node *p){
        if(vis[p-pool]) {
            ans-=del[p-pool];
            return;
        }
        ll pre=ans;
        for(int i=0;i<26;i++){
            if(!p->ch[i]) continue;
            Get_size(p->ch[i]);
            p->size+=p->ch[i]->size;
        }
        if(p->size>=2) ans-=(ll)p->size*(p->size-1);
        del[p-pool]=pre-ans; vis[p-pool]=1;
    }
    
    int main()
    {
        scanf("%s",s);
        n=strlen(s);
        
        root=&pool[++cnt];
        last=root;
        for(int i=0;i<n;i++) insert(s[i]-'a');
        
        node *tmp=last;
        for(;tmp!=root;tmp=tmp->pa) tmp->size=1;
        ans=(ll)n*(n+1)/2*(n-1);
        Get_size(root);
        
        printf("%lld
    ",ans+(ll)n*(n-1));
        
        return 0;
    }
    
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    PAT顶级 1015 Letter-moving Game (35分)
    PAT顶级 1008 Airline Routes (35分)(有向图的强连通分量)
    PAT顶级 1025 Keep at Most 100 Characters (35分)
    PAT顶级 1027 Larry and Inversions (35分)(树状数组)
    PAT 顶级 1026 String of Colorful Beads (35分)(尺取法)
    PAT顶级 1009 Triple Inversions (35分)(树状数组)
    Codeforces 1283F DIY Garland
    Codeforces Round #438 A. Bark to Unlock
    Codeforces Round #437 E. Buy Low Sell High
    Codeforces Round #437 C. Ordering Pizza
  • 原文地址:https://www.cnblogs.com/lindalee/p/10702640.html
Copyright © 2011-2022 走看看