【AHOI2013】【BZOJ3238】差异

来源:互联网 发布:淘宝店铺如何靠前 编辑:程序博客网 时间:2024/06/05 04:26

Description

这里写图片描述

Input

一行,一个字符串S

Output

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

Sample Input

cacao
Sample Output

54

HINT

2<=N<=500000,S由小写英文字母组成

后缀自动机的性质:

5.两个串的最长公共后缀,位于这两个串对应状态在Parent树上的最近公共祖先状态.

那么我们把原题里后缀的最长公共前缀反过来,把原串反过来建SAM就变成了最长公共后缀
然后题意就是求一个串所有前缀的最长公共后缀长度之和
我们可以在parent树上进行树形DP(按Po姐的说法其实就是在后缀树上DP?)统计每个点是多少点的LCA
对一个点统计子树两两right集合大小之积的和乘以深度
(别忘了是让你减掉这个东西)

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define MAXN 1000100using namespace std;char ch[MAXN];int top;long long ans;struct edge{    int to;    edge *next;}e[MAXN],*prev[MAXN];void insert(int u,int v){    e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];}struct sam{    int last,cnt,p,q,np,nq;    int len[MAXN],fa[MAXN],a[MAXN][26],size[MAXN];    sam()    {        last=++cnt;    }    void insert(int c)    {        p=last;np=last=++cnt;len[np]=len[p]+1;size[np]=1;        while (!a[p][c]&&p) a[p][c]=np,p=fa[p];        if (!p) fa[np]=1;        else        {            q=a[p][c];            if (len[q]==len[p]+1)   fa[np]=q;            else            {                nq=++cnt;len[nq]=len[p]+1;                memcpy(a[nq],a[q],sizeof(a[q]));                fa[nq]=fa[q];                fa[q]=fa[np]=nq;                while (a[p][c]==q)  a[p][c]=nq,p=fa[p];            }        }    }}sam;void dfs(int x,int f){    for (edge *i=prev[x];i;i=i->next)    {        dfs(i->to,x);        sam.size[x]+=sam.size[i->to];    }    if (x==1)   return;    sam.len[x]-=sam.len[f];    ans-=(long long)sam.size[x]*(sam.size[x]-1)*sam.len[x];}int main(){    scanf("%s",ch);int Len=strlen(ch);    for (int i=Len-1;i>=0;i--)  sam.insert(ch[i]-'a');    ans=(long long)(Len-1)*Len*(Len+1)>>1;    for (int i=2;i<=sam.cnt;i++)    insert(sam.fa[i],i);    dfs(1,0);    cout<<ans<<endl;}
1 0
原创粉丝点击