bzoj 3238: [Ahoi2013]差异

来源:互联网 发布:如何设计一个软件 编辑:程序博客网 时间:2024/04/29 20:50

Description

   一个长度为 N 的字符串 S ,令 Ti 表示它从第 i 个字符开始的后缀。求:

1i<jNlen(Ti)+len(Tj)2lcp(Ti,Tj)


   其中,len(a)表示a的长度,lcp(a,b) 表示a,b的最长公共前缀长度。
   
   
   

Solution:

   首先我们可以很快算出前面两个 len 的答案,所以只需减去 2lcp(Ti,Tj)

   用后缀自动机构建出后缀树,然后在后缀树上 dp ,记录一个 Size(x) 表示后缀树上以节点 x 为根的子树里面有多少个后缀节点。然后一次遍历子树,对于一个子树 uans=depthSize[u]Size[cnt]2,Size[cnt]+=Size[u]

   最后如果节点 x 也是一个后缀节点,那么ans=depthSize[cnt]2,Size[cnt]++
   
   
   

Code:

#include <cstdio>#include <cmath>#include <cstring>#include <cstdlib>#include <algorithm>#include <iostream>using namespace std;char str[500010]="\0";struct sam{    int ch[26];    int lenth;    int fail;}pot[1000010]={{{0},0,0}};int New[500010]={0};int pp=0;int First[1000010]={0};int N;struct bian_{    int to;    int next;    int dist;}bian[1000010]={{0,0,0}};int Size[1000010]={0};long long ans=0;void Addbian(int p,int q,int r,int k){    bian[k].to=q;    bian[k].dist=r;    bian[k].next=First[p];    First[p]=k;    return;}void Add(int t,int c){    int cnt=New[t-1];New[t]=++pp;pot[New[t]].lenth=pot[New[t-1]].lenth+1;    for(;cnt!=0 && pot[cnt].ch[c]==0;cnt=pot[cnt].fail)        pot[cnt].ch[c]=New[t];    if(cnt==0) pot[New[t]].fail=1;    else    {        int q=pot[cnt].ch[c];        if(pot[cnt].lenth+1==pot[q].lenth)            pot[New[t]].fail=q;        else        {            pp++;pot[pp]=pot[q];pot[pp].lenth=pot[cnt].lenth+1;            pot[q].fail=pot[New[t]].fail=pp;            for(;cnt!=0 && pot[cnt].ch[c]==q;cnt=pot[cnt].fail)                pot[cnt].ch[c]=pp;        }    }    return;}void dfs(int cnt,int depth){    for(int i=First[cnt];i!=0;i=bian[i].next)    {        int u=bian[i].to;        dfs(u,depth+bian[i].dist);        ans-=(long long)depth*Size[u]*Size[cnt]*2;        Size[cnt]+=Size[u];    }    if(New[pot[cnt].lenth]==cnt)    {        ans-=(long long)depth*Size[cnt]*2;        Size[cnt]++;    }    return;}int main(){    scanf("%s",str+1);    N=strlen(str+1);    New[0]=++pp;    for(int i=1;i<=N;i++)    {        Add(i,str[N-i+1]-'a');        ans+=(long long)i*(N-1);    }    for(int i=2;i<=pp;i++)        Addbian(pot[i].fail,i,pot[i].lenth-pot[pot[i].fail].lenth,i-1);    dfs(1,0);    cout<<ans<<endl;    return 0;}
0 0
原创粉丝点击