BZOJ 3238 [Ahoi2013]差異 後綴自動機

題目大意:
這裏寫圖片描述

len(Ti)+len(Tj)枚舉一下就好,主要是如何算sigma{lcp(Ti,Tj)}

將原串反過來建後綴自動機,兩個節點的lca即最長子串就是這兩個節點代表的串的lcp

於是枚舉、DP一下即可

#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 500005
using namespace std;
typedef long long LL;
struct Node {
    Node *ch[26],*pa;
    int val,cnt,siz;
    bool vis;
    Node() {}
    Node(int _val):val(_val),cnt(0),siz(0),pa(NULL),vis(false) {
        memset(ch,0,sizeof ch);
    }
    void* operator new(size_t) {
        static Node *C,*mempool;
        if(C==mempool) mempool=(C=new Node[1<<20])+(1<<20);
        return C++;
    }
}*root=new Node(0),*last;
void extend(char c) {
    int z=c-'a';
    Node *p=last,*np=new Node(p->val+1);
    last=np;
    while(p && !p->ch[z]) p->ch[z]=np, p=p->pa;
    if(!p) {
        np->pa=root;
        return ;
    }
    Node* q=p->ch[z];
    if(q->val==p->val+1) {
        np->pa=q;
        return ;
    }
    Node* nq=new Node(p->val+1);
    nq->pa=q->pa;
    q->pa=np->pa=nq;
    memcpy(nq->ch,q->ch,sizeof nq->ch);
    while(p && p->ch[z]==q) p->ch[z]=nq, p=p->pa;
    return ;
}
void init(char s[]) {
    last=root;
    int len=strlen(s);
    Node* o=root;
    for(int i=0;i<len;i++)
        extend(s[i]), o=o->ch[s[i]-'a'], o->siz++, o->cnt++;
    return ;
}
LL solve() {
    static Node *q[N*2],*s[N*2];
    static int t[N];
    LL tmp=0;
    int l=0,r=0;
    q[r++]=root;
    while(l<r) {
        Node* o=q[l++];
        t[o->val]++;
        for(int i=0;i<26;i++)
            if(o->ch[i] && !o->ch[i]->vis)
                q[r++]=o->ch[i], o->ch[i]->vis=true;
    }
    for(int i=1;i<=r;i++) t[i]+=t[i-1];
    for(int i=r-1;~i;i--) s[t[q[i]->val]--]=q[i];
    for(int i=r;i;i--)
        if(s[i]->pa)
            s[i]->pa->siz+=s[i]->siz;
    for(int i=1;i<r;i++) {
        tmp+=(LL)q[i]->pa->cnt*q[i]->siz*q[i]->pa->val;
        q[i]->pa->cnt+=q[i]->siz;
    }
    return tmp;
}
int main() {
    static char s[N],str[N];
    scanf("%s",str);
    int len=strlen(str);
    for(int i=0;i<len;i++) s[i]=str[len-i-1];
    init(s);
    LL ans=0;
    for(int i=0;i<len;i++) ans+=(LL)(i+1)*(len-1);
    printf("%lld\n",ans-solve()*2);
    return 0;
}
發佈了110 篇原創文章 · 獲贊 6 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章