[bzoj2534]Uva10829L-gap字符串
来源:互联网 发布:php音频上传代码 编辑:程序博客网 时间:2024/06/07 00:56
题目描述
有一种形如uvu形式的字符串,其中u是非空字符串,且V的长度正好为L,那么称这个字符串为L-Gap字符串
给出一个字符串S,以及一个正整数L,问S中有多少个L-Gap子串.
L≤10 字符串长≤50000
分析
这道题难度挺大的。。。
考虑一个合法的UVU串。假设两个U结束位置分别是i,j(i < j)。
设两个前缀i,j的最长公共后缀长度为len。那么i,j合法时满足以下两个条件:
1. i+L < j
2. i+L+len≥j
现在考虑给字符串建后缀自动机,然后对于两个前缀,分别是i和j,在sam上跑到两个不同节点,这两个节点在fail树上lca所表示最长后缀的长度就是i,j的最长公共后缀了。
那么一个解法就出来了:用平衡树维护一棵子树所有的前缀,递归完所有儿子后,每个平衡树两两合并,并且合并前其中一棵子树的所有前缀拿出来到另一个平衡树上查询。用启发式合并即可做到
我用的是treap
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int N=50005,M=N*2;typedef long long LL;int n,m,L,tot,last,e[M][256],step[M],fail[M],h[M],E[M],nxt[M],root[M],son[N][2],fix[N],key[N],size[N],fa[N],D[N];LL ans;char s[N];void Extend(int c){ int np=++m,p=last,q,nq; last=np; step[np]=step[p]+1; for (;p>=0 && !e[p][c];p=fail[p]) e[p][c]=np; if (p<0) fail[np]=0;else { q=e[p][c]; if (step[p]==step[q]-1) fail[np]=q;else { nq=++m; fail[nq]=fail[q]; memcpy(e[nq],e[q],sizeof(e[q])); step[nq]=step[p]+1; fail[np]=fail[q]=nq; for (;p>=0 && e[p][c]==q;p=fail[p]) e[p][c]=nq; } }}void add(int x,int y){ E[++tot]=y; nxt[tot]=h[x]; h[x]=tot;}void calc(int x,int y,int sig){ if (!x) return; if (key[x]>y) calc(son[x][0],y,sig); else { ans+=sig*size[son[x][0]]+sig; if (key[x]<y) calc(son[x][1],y,sig); }}void Rotate(int x,int t){ int y=fa[x]; fa[x]=fa[y]; if (fa[y]>0) { if (son[fa[y]][0]==y) son[fa[y]][0]=x;else son[fa[y]][1]=x; } son[y][t]=son[x][t^1]; if (son[y][t]>=0) fa[son[y][t]]=y; son[x][t^1]=y; fa[y]=x; size[y]=size[son[y][0]]+size[son[y][1]]+1; size[x]=size[son[x][0]]+size[son[x][1]]+1;}void insert(int x,int y){ size[x]++; if (key[y]<key[x]) { if (son[x][0]) { insert(son[x][0],y); if (fix[x]>fix[son[x][0]]) Rotate(son[x][0],0); }else { son[x][0]=y; fa[y]=x; son[y][0]=son[y][1]=0; size[y]=1; if (fix[x]>fix[y]) Rotate(y,0); } }else { if (son[x][1]) { insert(son[x][1],y); if (fix[x]>fix[son[x][1]]) Rotate(son[x][1],1); }else { son[x][1]=y; fa[y]=x; son[y][0]=son[y][1]=0; size[y]=1; if (fix[x]>fix[y]) Rotate(y,1); } }}void dfs(int x){ for (int i=h[x];i;i=nxt[i]) { dfs(E[i]); if (!root[x]) root[x]=root[E[i]]; else if (root[E[i]]) { if (size[root[x]]<size[root[E[i]]]) root[x]^=root[E[i]]^=root[x]^=root[E[i]]; D[tot=1]=root[E[i]]; for (int j=1;j<=tot;j++) { int k=D[j]; if (son[k][0]) D[++tot]=son[k][0]; if (son[k][1]) D[++tot]=son[k][1]; k=key[k]; calc(root[x],k+L+step[x],1); calc(root[x],k+L,-1); calc(root[x],k-L-1,1); calc(root[x],k-L-step[x]-1,-1); } for (int j=1;j<=tot;j++) { insert(root[x],D[j]); if (fa[D[j]]==0) root[x]=D[j]; } } }}int main(){ srand(65870762); scanf("%d%s",&L,s+1); fail[0]=-1; n=strlen(s+1); for (int i=1;i<=n;i++) Extend(s[i]); for (int i=1;i<=m;i++) add(fail[i],i); tot=0; for (int i=1,j=0;i<=n;i++) { for (;j>0 && e[j][s[i]]==0;j=fail[j]); if (e[j][s[i]]>0) { j=e[j][s[i]]; root[j]=++tot; key[tot]=i; fix[tot]=rand()*109+rand(); size[tot]=1; } } dfs(0); printf("%lld\n",ans); return 0;}
1 0
- [bzoj2534]Uva10829L-gap字符串
- [BZOJ2534]Uva10829L-gap字符串(后缀数组+st表)
- bzoj2534 Uva10829L-gap字符串(SA+lcp同bzoj2119)
- bzoj 2534: Uva10829L-gap字符串 后缀数组+线段树合并
- bzoj 2534: Uva10829L-gap字符串 (后缀数组+ST表)
- Gap
- GAP
- Generation Gap
- GAP Analysis
- 4479. Gap
- Phone Gap
- UNRESOLVABLE GAP
- Prime Gap
- Prime Gap
- dataguard gap
- Prime Gap
- Prime Gap
- Maximum Gap
- Maven resources plugin 损坏二进制数据
- XMPP协议详解
- 最大子序列、最长递增子序列、最长公共子串、最长公共子序列、字符串编辑距离
- 全面了解 Nginx 主要应用场景
- Permutations
- [bzoj2534]Uva10829L-gap字符串
- 二叉树2(二叉查找树的插入、查找、删除、遍历)
- java.lang.ClassNotFoundException:com.mysql.jdbc.Driver
- css代码语法
- 你想知道的 Watch App 开发
- Permutations II
- nohup
- 逻辑回归模型(Logistic Regression, LR)
- 【机器学习实战】k-近邻算法