HDU5421 Victor and String 和 APIO2014 回文串
两道差不多的题,都是回文自动机right集合处理相关。
Victor and String
Victor loves to play with string. He thinks a string is charming as the string is a palindromic string.
Victor wants to play n times. Each time he will do one of following four operations.
- add a char c to the beginning of the string. 
- add a char c to the end of the string. 
- ask the number of different charming substrings. 
- ask the number of charming substrings, the same substrings which starts in different location has to be counted. 
At the beginning, Victor has an empty string.
1≤n≤100000
题解
来自翁文涛《回文树及其应用》。

CO int N=200000+10;
namespace PAM{
	int str[N],L,R;
	int tot,last[2];
	int ch[N][26],fa[N],len[N],dep[N];
	LL ans;
	IN int new_node(int l){
		fill(ch[tot],ch[tot]+26,0);
		len[tot]=l,dep[tot]=0;
		return tot++;
	}
	IN void init(int n){
		memset(str,-1,sizeof str),L=n,R=n-1;
		tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
		last[0]=last[1]=1;
		ans=0;
	}
	int get_fail(int x,bool d){
		if(d)while(str[R-len[x]-1]!=str[R]) x=fa[x];
		else while(str[L+len[x]+1]!=str[L]) x=fa[x];
		return x;
	}
	void extend(int c,bool d){
		if(d) str[++R]=c;
		else str[--L]=c;
		int p=get_fail(last[d],d);
		if(!ch[p][c]){
			int cur=new_node(len[p]+2);
			fa[cur]=ch[get_fail(fa[p],d)][c];
			ch[p][c]=cur;
			dep[cur]=dep[fa[cur]]+1;
		}
		last[d]=ch[p][c];
		if(len[last[d]]==R-L+1) last[d^1]=last[d];
		ans+=dep[last[d]];
	}
}
void real_main(int n){
	PAM::init(n);
	while(n--){
		int opt=read<int>();
		if(opt<=2){
			char c[2];scanf("%s",c);
			PAM::extend(c[0]-'a',opt-1);
		}
		else if(opt==3) printf("%d\n",PAM::tot-2);
		else if(opt==4) printf("%lld\n",PAM::ans);
	}
}
int main(){
	for(int n;~scanf("%d",&n);) real_main(n);
	return 0;
}
我发现初始化的时候必须memset。这是因为跳fail的时候可能会越界。
然后我加了一些特判,可以去掉memset。
namespace PAM{
	int str[N],L,R;
	int tot,last[2];
	int ch[N][26],fa[N],len[N],dep[N];
	LL ans;
	IN int new_node(int l){
		fill(ch[tot],ch[tot]+26,0);
		len[tot]=l,dep[tot]=0;
		return tot++;
	}
	IN void init(int n){
		L=n,R=n-1;
		tot=0,new_node(0),new_node(-1),fa[0]=fa[1]=1;
		last[0]=last[1]=1;
		ans=0;
	}
	int get_fail(int x,bool d){
		if(d)while(assert(L<=R-len[x]-1 and R-len[x]-1<=R),str[R-len[x]-1]!=str[R]) x=fa[x];
		else while(assert(L<=L+len[x]+1 and L+len[x]+1<=R),str[L+len[x]+1]!=str[L]) x=fa[x];
		return x;
	}
	void extend(int c,bool d){
		if(d) str[++R]=c;
		else str[--L]=c;
		int p=get_fail(len[last[d]]==R-L?fa[last[d]]:last[d],d); // edit
		if(!ch[p][c]){
			int cur=new_node(len[p]+2);
			fa[cur]=ch[get_fail(fa[p],d)][c];
			ch[p][c]=cur;
			dep[cur]=dep[fa[cur]]+1;
		}
		last[d]=ch[p][c];
		if(len[last[d]]==R-L+1) last[d^1]=last[d];
		ans+=dep[last[d]];
	}
}
APIO2014 回文串
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最大出现值。
数据满足1≤字符串长度≤300000。
题解

co int N=300000+10;
int last=1,tot=1;
int ch[N][26],fa[N]={1,1},len[N]={0,-1},siz[N];
char s[N];
int get_fa(int x,int i){
	while(s[i-len[x]-1]!=s[i]) x=fa[x];
	return x;
}
void extend(int i){
	int p=get_fa(last,i);
	int x=ch[p][s[i]-'a'];
	if(!x){
		x=++tot;
		fa[x]=ch[get_fa(fa[p],i)][s[i]-'a'];
		len[x]=len[p]+2;
		ch[p][s[i]-'a']=x;
	}
	++siz[x];
	last=x;
}
int main(){
	scanf("%s",s+1);int n=strlen(s+1);
	for(int i=1;i<=n;++i) extend(i);
	for(int i=tot;i>=2;--i) siz[fa[i]]+=siz[i];
	LL ans=0;
	for(int i=1;i<=tot;++i) ans=max(ans,(LL)siz[i]*len[i]);
	printf("%lld\n",ans);
	return 0;
}
后缀自动机做法
http://hzwer.com/6847.html
https://blog.csdn.net/u012288458/article/details/51785834
每找到一个回文串,就在所有的串中查找出现了多少次
因为暴力跳非常的慢,所以用倍增优化
每次查询都是从末尾节点开始,倍增找到最后一个长度大于等于p的节点
manacher算法证明了本质不同的回文串只有\(O(n)\)个,复杂度\(O(n\log n)\)
第一次写直接做的manacher算法,分析了一会儿。求偶回文串的时候以左端点代替空隙,然后其他操作基本一致。
co int N=6e5;
// Suffix Automaton
int last=1,tot=1;
int ch[N][26],fa[N],len[N],siz[N],pos[N]; // pos:out->in
void extend(int c,int po){
	int p=last,cur=last=++tot;
	len[cur]=len[p]+1,siz[cur]=1,pos[po]=cur;
	for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
	if(!p) fa[cur]=1;
	else{
		int q=ch[p][c];
		if(len[q]==len[p]+1) fa[cur]=q;
		else{
			int clone=++tot;
			memcpy(ch[clone],ch[q],sizeof ch[q]);
			fa[clone]=fa[q],len[clone]=len[p]+1;
			fa[cur]=fa[q]=clone;
			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
		}
	}
}
int cnt[N],id[N],anc[N][21];
ll ans;
void query(int l,int r){
	int p=pos[r];
	for(int i=20;i>=0;--i)
		if(len[anc[p][i]]>=r-l+1) p=anc[p][i];
	ans=max(ans,(ll)siz[p]*(r-l+1));
}
char s[N];
int n,p[N];
int main(){
	scanf("%s",s+1),n=strlen(s+1);
	for(int i=1;i<=n;++i) extend(s[i]-'a',i);
// build
	for(int i=1;i<=tot;++i) ++cnt[len[i]];
	for(int i=1;i<=n;++i) cnt[i]+=cnt[i-1];
	for(int i=1;i<=tot;++i) id[cnt[len[i]]--]=i;
	for(int i=tot;i;--i){
		int p=id[i];
		siz[fa[p]]+=siz[p];
	}
	for(int i=1;i<=tot;++i){
		int p=id[i];
		anc[p][0]=fa[p];
		for(int j=1;j<=20;++j) anc[p][j]=anc[anc[p][j-1]][j-1];
	}
// Manacher
	s[0]='@',s[n+1]='#';
	int mx=0,id=1;
	for(int i=1;i<n;++i){ // even, represent with left vertice
		if(mx>i) p[i]=min(mx-i,p[2*id-i]);
		else p[i]=0;
		while(s[i+p[i]+1]==s[i-p[i]])
			++p[i],query(i-p[i]+1,i+p[i]);
		if(p[i]+i>mx) mx=p[i]+i,id=i;
	}
	mx=0,id=1;
	for(int i=1;i<=n;++i){ // odd
		if(mx>i) p[i]=min(mx-i,p[2*id-i]);
		else p[i]=1,query(i-p[i]+1,i+p[i]-1);
		while(s[i+p[i]]==s[i-p[i]])
			++p[i],query(i-p[i]+1,i+p[i]-1);
		if(p[i]+i>mx) mx=p[i]+i,id=i;
	}
	printf("%lld\n",ans);
	return 0;
}
HDU5421 Victor and String 和 APIO2014 回文串的更多相关文章
- 3676: [Apio2014]回文串
		3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MB Submit: 1740 Solved: 744 [Submit][Status ... 
- 3676: [Apio2014]回文串   求回文串长度与出现次数的最大值
		「BZOJ3676」[Apio2014] 回文串 Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所 ... 
- BZOJ 3676: [Apio2014]回文串
		3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2013 Solved: 863[Submit][Status ... 
- bzoj 3676: [Apio2014]回文串 回文自动机
		3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 844 Solved: 331[Submit][Status] ... 
- [模板] 回文树/回文自动机 && BZOJ3676:[Apio2014]回文串
		回文树/回文自动机 放链接: 回文树或者回文自动机,及相关例题 - F.W.Nietzsche - 博客园 状态数的线性证明 并没有看懂上面的证明,所以自己脑补了一个... 引理: 每一个回文串都是字 ... 
- 【BZOJ 3676】 3676: [Apio2014]回文串 (SAM+Manacher+倍增)
		3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2343 Solved: 1031 Description 考 ... 
- [BZOJ3676][APIO2014]回文串(Manacher+SAM)
		3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3097 Solved: 1408[Submit][Statu ... 
- [Bzoj3676][Apio2014]回文串(后缀自动机)(parent树)(倍增)
		3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 3396 Solved: 1568[Submit][Statu ... 
- 【bzoj3676】[Apio2014]回文串 —— 回文自动机的学习
		写题遇上一棘手的题,[Apio2014]回文串,一眼看过后缀数组+Manacher.然后就码码码...过是过了,然后看一下[Status],怎么慢这么多,不服..然后就搜了一下,发现一种新东西——回文 ... 
随机推荐
- scala 正则
			package com.program import scala.util.matching.Regex object RegexTest { def main(args: Array[String] ... 
- Maven设置MAVEN_OPTS环境变量
			原文地址:https://blog.csdn.net/porsche_gt3rs/article/details/78787491 一 原因: 运行mvn命令实际是执行java命令,既然是运行java ... 
- Springboot Actuator之五:Springboot中的HealthAggregator、新增自定义Status
			springboot的actuator内置了/health的endpoint,很方便地规范了每个服务的健康状况的api,而且HealthIndicator可以自己去扩展,增加相关依赖服务的健康状态,非 ... 
- 离线方式快速安装python模块以及相关依赖模块
			一般公司的服务器都是和外网隔离的,这个如果没有内部pip源的话,想要安装python的模块就需要去python官网一个一个下载依赖模块的包,然后逐个安装,这样做非常耗时间. 我们今天用的办法就是现在我 ... 
- vim中常用折叠命令
			最常用3个折叠命令 .反复打开关闭折叠:za (意思就是,当光标处折叠处于打开状态,za关闭之,当光标处折叠关闭状态,打开之) .打开全部折叠:zR .关闭全部折叠:zM 小试折叠: :set fdm ... 
- Maven:repositories、distributionManagement、pluginRepositories中repository的区别
			本文链接:https://blog.csdn.net/netyeaxi/article/details/95804076 目录 一.repositories中的repository 二.distrib ... 
- Java+Python+前端 学习资料大全 百度云盘
			Java架构师3大阶段 链接:https://pan.baidu.com/s/1DlXh33y5t4cZUmZH0cLvCw 提取码:5s76 2019前端架构阶段 链接:https://pan.ba ... 
- C#读写调整设置UVC摄像头画面-亮度
			有时,我们需要在C#代码中对摄像头的亮度进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像 ... 
- Echarts X轴多项百分比的展示
			app.title = '堆叠柱状图'; option = { tooltip : { trigger: 'axis', axisPointer : { // 坐标轴指示器,坐标轴触发有效 type ... 
- 使用Supervisord软件管理go服务进程
			一.介绍Supervisord软件1.什么是Supervisord?Supervisord是一个非常优秀的进程管理工具,使用Python开发.它可以在类UNIX系统的方式让用户来准确地监视和控制后台一 ... 
