【LOJ141】回文子串(回文自动机)

本文详细介绍了双向PAM算法的应用,通过维护最长回文前缀和最长回文后缀来解决回文串问题。文中提供了完整的C++实现代码,并解释了如何在字符串两端分别添加字符时更新数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门


题解:

双向PAM板子,同时维护最长回文前缀和最长回文后缀,和原来没什么区别,只需要注意当整个串成为一个回文串的时候需要维护一下两个指针。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	static cs int Rlen=1<<22|1;
	static char buf[Rlen],*p1,*p2;
	
	inline char get_char(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline char peek(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1;
	}
	
	template<typename T>
	inline T get(){
		char c;
		while(!isdigit(c=gc()));T num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int getint(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=4e5+5;
int son[N][26],fa[N],len[N],dep[N],now;
char s[N<<1];
int l=N,r=N-1,llast,rlast;

ll ans;

inline void init(){fa[0]=1,len[1]=-1,now=1;}

inline void push_front(char c){
	s[--l]=c;int p=llast;c-='a';
	while(s[l+len[p]+1]!=s[l])p=fa[p];
	if(!son[p][c]){
		len[++now]=len[p]+2;
		int k=fa[p];
		while(s[l+len[k]+1]!=s[l])k=fa[k];
		fa[now]=son[k][c],dep[now]=dep[fa[now]]+1;
		son[p][c]=now;
	}
	llast=son[p][c];
	if(len[llast]==r-l+1)rlast=llast;
	ans+=dep[llast];
}

inline void push_back(char c){
	s[++r]=c;int p=rlast;c-='a';
	while(s[r-len[p]-1]!=s[r])p=fa[p];
	if(!son[p][c]){
		len[++now]=len[p]+2;
		int k=fa[p];
		while(s[r-len[k]-1]!=s[r])k=fa[k];
		fa[now]=son[k][c],dep[now]=dep[fa[now]]+1;
		son[p][c]=now;
	}
	rlast=son[p][c];
	if(len[rlast]==r-l+1)llast=rlast;
	ans+=dep[rlast];
}

int Q;
signed main(){
//	freopen("pam.in","r",stdin);//freopen("pam.out","w",stdout);
	init();
	while(islower(peek()))push_back(gc());
	Q=getint();
	while(Q--)switch(getint()){
		case 1:while(islower(peek()))push_back(gc());break;
		case 2:while(islower(peek()))push_front(gc());break;
		case 3:std::cout<<ans<<"\n";break;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值