ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

CF700E Cool Slogans / YbtOJ「字符串算法」第3章 后缀自动机 G. 重复子串 题解--zhengjun

2022-06-11 16:05:16  阅读:130  来源: 互联网

标签:rt 后缀 cur zhengjun int 题解 fa YbtOJ 字符串


题目大意

选出一个字符串序列 \(s\),使得对于每一个 \(s_i\),都是原串的子串,且每个 \(s_i\) 在 \(s_{i-1}\) 中都出现过至少两次,求最大的序列长度。

思路

发现其实可以做到让所有选出的字符串都是上一个字符串的后缀,因为如果后面留了一个尾巴,那么前面的字符串把这个尾巴砍了是不影响答案的。

然后发现,其实这个就是 SAM 在 parent 树上的顺序(在 parent 树上,儿子一定是父亲的后缀),那么,只需要从上往下 \(dp\),记录上一个选择的后缀为 \(fa\),当前在 \(u\),那么就是要判断,\(s_{fa}\) 是否在 \(s_u\) 中出现了至少两次,然后我们只需要找到当前的 \(endpos\) 集合,查询区间中是否存在一个数即可,这里可以用可持久化线段树合并完成。

代码

#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=4e5+10,M=2e7;char s[N];
int n,ch[N][26],lnk[N],len[N],pos[N],las,root[N],ls[M],rs[M],cnt,tot,cur[N],f[N],st[N],ans;
void update(int &rt,int cur,int l=1,int r=n){
	if(!rt)rt=++cnt;if(l==r)return;int mid=(l+r)>>1;if(cur<=mid)update(ls[rt],cur,l,mid);else update(rs[rt],cur,mid+1,r);
}
void merge(int &x,int y,int l=1,int r=n){
	if(!x||!y)return void(x|=y);ls[++cnt]=ls[x];rs[cnt]=rs[x];x=cnt;if(l==r)return;
	int mid=(l+r)>>1;merge(ls[x],ls[y],l,mid);merge(rs[x],rs[y],mid+1,r);
}
bool query(int rt,int L,int R,int l=1,int r=n){
	if(!rt)return 0;if(L<=l&&r<=R)return 1;int mid=(l+r)>>1;
	if(L<=mid&&query(ls[rt],L,R,l,mid))return 1;if(mid<R&&query(rs[rt],L,R,mid+1,r))return 1;return 0;
}
void extend(int c,int i){
	int now=++tot,p=las,q,ne;len[now]=len[las]+1;pos[now]=i;while(~p&&!ch[p][c])ch[p][c]=now,p=lnk[p];if(!~p)lnk[now]=0;else{
		q=ch[p][c];if(len[q]==len[p]+1)lnk[now]=q;else{ne=++tot;len[ne]=len[p]+1;memcpy(ch[ne],ch[q],sizeof ch[q]);
			lnk[ne]=lnk[q];pos[ne]=pos[q];while(~p&&ch[p][c]==q)ch[p][c]=ne,p=lnk[p];lnk[now]=lnk[q]=ne;}
	}las=now;update(root[now],i);
}
bool cmp(int x,int y){return len[x]<len[y];}
int main(){
	scanf("%d%s",&n,s+1);lnk[0]=-1;for(int i=1;i<=n;i++)extend(s[i]-'a',i);for(int i=1;i<=tot;i++)cur[i]=i;
	sort(cur+1,cur+1+tot,cmp);for(int i=tot,u,fa;u=cur[i],fa=lnk[u],i>=1;i--)merge(root[fa],root[u]);
	for(int i=1,u,fa;u=cur[i],fa=lnk[u],i<=tot;ans=max(ans,f[u]),i++)if(!fa)f[u]=1,st[u]=u;
		else if(query(root[st[fa]],pos[u]-len[u]+len[st[fa]],pos[u]-1))f[u]=f[fa]+1,st[u]=u;else f[u]=f[fa],st[u]=st[fa];
	cout<<ans;return 0;
}

有问题请指教,谢谢--zhengjun

标签:rt,后缀,cur,zhengjun,int,题解,fa,YbtOJ,字符串
来源: https://www.cnblogs.com/A-zjzj/p/16366089.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有