后缀自动机+DP BZOJ 3238 差异

来源:互联网 发布:bilibili视频编辑软件 编辑:程序博客网 时间:2024/06/05 09:38

分析:
其实题目就是要求任意两个后缀T[i]和T[j] (i< j) 的 LCP长度之和。
首先对输入的字符串反转后建立SAM。
令 一个节点的Max表示它代表的最长子串。
推论1: 原串中的两个后缀的LCP长度等于后缀树上两个节点的LCA 的 Max.
基于这个推论,只需要枚举LCA,讨论子树与子树之间的组合数问题。
虽然理论上要建立后缀树,但代码里并不用真的建一棵树再DFS。
具体做法如下:
推论2: Max更大的节点一定在后缀树中深度更大
根据这个推论,我们可以按照Max从小到大进行排序,得到一个序列dfn[]就是深度从浅到深的节点编号,可以进行DP。
考虑到1<=Max<=n, 代码中用的是O(n)的基数排序。
注意: DP中累加size的时候,建立的辅助节点nq没有算在其中。

代码:

/**************************************************************    Problem: 3238    User: spark    Language: C++    Result: Accepted    Time:3072 ms    Memory:244452 kb****************************************************************/#include<cstdio>#include<iostream>#include<cstdlib>#include<cmath>#include<cstring>#define LL long longusing namespace std;const int maxn=1000000+5;int tot=1,last=1,n,dfn[maxn],cnt[maxn];char s[maxn];struct node{    int Next[26];    int Max,size,pre,sons;}T[maxn<<1];template <typename T>inline void _read(T &x){    char ch=getchar(); bool mark=false;    for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;    for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';    if(mark)x=-x;}void Insert(char x){    int id= x-'a';    int np= ++tot,cur=last;    T[np].Max=T[last].Max+1; T[np].size=T[np].sons=1;    while(cur){        if(!T[cur].Next[id])  T[cur].Next[id]= np;        else {            int v= T[cur].Next[id];            if(T[v].Max==T[cur].Max+1) T[np].pre=v;            else{                int nq= ++tot;                memcpy(T[nq].Next,T[v].Next,sizeof(T[v].Next));                T[nq].Max=T[cur].Max+1;                T[nq].pre=T[v].pre; T[v].pre= nq;                 T[np].pre= nq;                 for(int i= cur;T[i].Next[id]==v;i=T[i].pre)                    T[i].Next[id]=nq;            }             break;        }        cur=T[cur].pre;    }    if(!T[np].pre)T[np].pre=1;    last=np;}LL Count(){    int i;    LL ans=0;    for(i=1;i<=tot;i++) cnt[T[i].Max]++;    for(i=1;i<=n;i++)cnt[i]+=cnt[i-1];    for(i=1;i<=tot;i++)dfn[cnt[T[i].Max]--]= i;    // cout<<"dfn: ";for(i=1;i<=tot;i++)cout<<dfn[i]<<" ";cout<<endl;    for(i=tot;i>0;i--)T[T[dfn[i]].pre].size+=T[dfn[i]].size;    for(i=1;i<=tot;i++){        int fa= T[i].pre;        ans+= 1ll*T[fa].sons*T[fa].Max*T[i].size;        T[fa].sons+= T[i].size;    }    return ans;}int main(){    int i,j;    scanf("%s",s+1);    n= strlen(s+1);     for(i=n;i>0;i--)Insert(s[i]);    LL ans=0;    for(i=1;i<=n;i++) ans+= (1ll*i*(n-1));    cout<<ans-2*Count()<<endl;    return 0;}
#include<cstdio>#include<iostream>#include<cstdlib>#include<algorithm>#include<cstring>#define Marx_is_dead true#define ll long longusing namespace std;template <typename T>inline void _read(T& x){    char t=getchar();bool sign=true;    while(t<'0'||t>'9'){if(t=='-')sign=false;t=getchar();}    for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';    if(!sign)x=-x;}int n,m;int last=1,root=1,tot=1;struct node{    int son[26];    int maxn,size,par,temp;};node Auto[2000005];char s[1000005];void insert(char ch){    int i,j,k,nq,p,q,t=ch-'a';    int np=++tot;    Auto[np].size=1;    Auto[np].temp=1;    Auto[np].maxn=Auto[last].maxn+1;    for(p=last;!Auto[p].son[t];p=Auto[p].par)Auto[p].son[t]=np;    if(!p)Auto[np].par=root;    else {        q=Auto[p].son[t];        if(Auto[q].maxn!=Auto[p].maxn+1){            nq=++tot;            memcpy(Auto[nq].son,Auto[q].son,sizeof(Auto[q].son));            //Auto[nq]=Auto[q];            Auto[nq].maxn=Auto[p].maxn+1;            Auto[nq].par=Auto[q].par;            Auto[q].par=nq;            Auto[np].par=nq;            for(;Auto[p].son[t]==q;p=Auto[p].par)Auto[p].son[t]=nq;        }        else Auto[np].par=q;    }    if(Auto[np].par==0)Auto[np].par=root;    last=np;}int cnt[1000005];int dfn[1000005];int main(){    int i,j,len;    scanf("%s",s+1);    len=strlen(s+1);    for(i=len;i;i--){        insert(s[i]);    }    ll ans=1ll*(len+1)*(len-1)*len/2;    for(i=1;i<=tot;i++)cnt[Auto[i].maxn]++;    for(i=1;i<=len;i++)cnt[i]+=cnt[i-1];    for(i=1;i<=tot;i++)dfn[cnt[Auto[i].maxn]--]=i;    for(i=tot;i;i--){        Auto[Auto[dfn[i]].par].size+=Auto[dfn[i]].size;    }    ll dec=0;    for(i=1;i<=tot;i++){        int fa=Auto[i].par;        dec+=1ll*Auto[fa].temp*Auto[i].size*Auto[fa].maxn;        Auto[fa].temp+=Auto[i].size;    }    cout<<ans-2*dec;}
0 0