BZOJ 3238 [Ahoi2013]差异 后缀自动机

来源:互联网 发布:js多图上传 编辑:程序博客网 时间:2024/04/29 18:56

题目大意:
这里写图片描述

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

将原串反过来建后缀自动机,两个节点的lca即最长子串就是这两个节点代表的串的lcp

于是枚举、DP一下即可

#include <cstdio>#include <algorithm>#include <cstring>#define N 500005using 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;}
0 0
原创粉丝点击