后缀自动机+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
- 后缀自动机+DP BZOJ 3238 差异
- BZOJ 3238 差异 [后缀自动机]
- bzoj 3238: [Ahoi2013]差异 (后缀自动机+树形dp)
- [后缀自动机][树形DP] BZOJ 3238: [Ahoi2013]差异
- BZOJ 3238 AHOI2013 差异 后缀自动机
- bzoj 3238: [Ahoi2013]差异 后缀自动机
- BZOJ 3238 [Ahoi2013]差异 后缀自动机
- [后缀自动机 构建后缀树 树形DP] BZOJ 3238 [Ahoi2013]差异
- 【BZOJ 3238】[Ahoi2013]差异 后缀自动机构造后缀树
- [BZOJ3238][Ahoi2013][后缀自动机][树形DP]差异
- BZOJ 2806 Cheat (后缀自动机+dp)
- 【bzoj3238】差异 后缀自动机
- [Ahoi2013]差异 后缀自动机
- BZOJ 3238 AHOI 2013 差异 后缀树
- bzoj 3238: [Ahoi2013]差异 后缀数组
- BZOJ 3238: [Ahoi2013]差异 后缀数组
- bzoj 3238: [Ahoi2013]差异 后缀树
- bzoj 3238 ahoi2013差异 后缀数组
- 谈心--生活不止步于乐观
- CSS-定位和浮动
- Hadoop2.0 HA 集群搭建步骤
- 新手入门的I/O简单基础知识
- linux NTP服务器搭建
- 后缀自动机+DP BZOJ 3238 差异
- PAT:A1077. Kuchiguse (0/20)
- 基础练习 闰年判断
- C语言文件读写标准I/O库函数的相关操作
- bzoj 1030 AC自动机+DP
- DockerInAction-Software installation simplified
- Biztalk AS2开发经验总结
- hdu1532-Drainage Ditches(最大流&EK)
- 悠悠web(1)-HTML基本结构