P8368 [LNOI2022] 串 题解

题目链接

题目分析#

题目要求我们构造一个最长的 T 序列,我们首先从每个 Ti 入手,思考如何安排才能合法。

容易观察到对于每个 Ti,合法的 Ti1 有两种方式构造,要么直接为上一个字符串左右端点平移得到,要么找到另外一个等于 Ti 的子串再平移得到,这似乎启发我们使用 SAM 对 endpos 集合进行维护,但思考后发现这似乎不容易实现,于是我们转换思考方式。

着眼于构造方式而非字符串,由于每次从大到小构造时,如果没有重复子串,构造过程相当于向左移动一个单位并且长度缩短,我们可以从中得到一个答案的下界:|s|2

如果加上重复子串呢,可以发现从右到左地更换匹配位置答案只会变坏,而从左到右则就相当于如果原先长度还没减完就移动到了左端点,现在从左往右更换则为其“续命”,可以让他继续移动,并且后面构造出的 T 也会在原串中出现至少两次,可以继续“续命”。

结合上述讨论,我们可以将 T 数组分为两种情况,分别为一段出现两次,一段出现一次与只出现一次的,后者答案的最大值即为 |s|2。前者由于必然经过一个出现过两次的字符串,我们可以用 SAM 在此处统计,每个左右端点分别为 lr,出现过两次的字符串对答案的贡献为 rl+1+nr2

代码#

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define ll long long
#define N 1500005
using namespace std;
string s[N];
int len[N<<1],fa[N<<1],nex[N<<1][27];
int head[N<<1],ne[N<<1],to[N<<1],en[N<<1],sum[N<<1];
int last=1,tot=1,e,ans=0,le;
void insert(int num){
	int p=last,np=++tot;last=np;
	len[np]=len[p]+1;
	en[np]=en[p]+1;sum[np]=1;
	for(;p && !nex[p][num];p=fa[p])nex[p][num]=np;
	if(!p) fa[np]=1;
	else{
		int q=nex[p][num];
		if(len[q]==len[p]+1) fa[np]=q;
		else{
			int clone=++tot;len[clone]=len[p]+1;
			fa[clone]=fa[q];fa[q]=fa[np]=clone;
			for(int i=1;i<=26;i++) nex[clone][i]=nex[q][i];
			for(;p && nex[p][num]==q;p=fa[p]) nex[p][num]=clone;
		}
	}
}
void addedg(int u,int v){
	to[++e]=v;ne[e]=head[u];head[u]=e;
	to[++e]=u;ne[e]=head[v];head[v]=e;
}
void dfs(int x,int fa){
	if(!en[x]) en[x]=0x3f3f3f3f;
	for(int i=head[x];i;i=ne[i]){
		int v=to[i];
		if(v==fa) continue;
		dfs(v,x);en[x]=min(en[x],en[v]);sum[x]+=sum[v];
	}
	if(sum[x]>1)ans=max(ans,len[x]+(le-en[x])/2);
}
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>s[i];
	for(int i=1;i<=n;i++){
		le=s[i].length();
		for(int j=0;j<le;j++) insert(s[i][j]-'a'+1);
		for(int j=2;j<=tot;j++){
			addedg(j,fa[j]);
		}
		dfs(1,0);
		ans=max(ans,le/2);
		cout<<ans<<endl;
		ans=0;
		for(int j=1;j<=e;j++)to[j]=ne[j]=0;
		for(int j=1;j<=tot;j++) head[j]=0;
		for(int j=1;j<=tot;j++) fa[j]=len[j]=sum[j]=en[j]=0;
		for(int j=1;j<=tot;j++) for(int k=1;k<=26;k++) nex[j][k]=0;
		tot=1;last=1;e=0;
	}
	
}

作者:eastcloud

出处:https://www.cnblogs.com/eastcloud/p/17090496.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   eastcloud  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示