其他分享
首页 > 其他分享> > 【CodeChef PALPROB】Palindromeness(回文自动机)

【CodeChef PALPROB】Palindromeness(回文自动机)

作者:互联网

传送门


题解:

建立回文自动机,维护每个点right集合大小。

然后维护halfhalfhalf指针,表示failfailfail树上第一个长度小于等于自己的一半的回文后缀。

在建立的时候暴力跳祖先的half更新答案,复杂度还是由均摊分析O(S)O(|S|)O(∣S∣)


代码:

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

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int get_s(char *s){
		int len=0;char c;
		while(isspace(c=gc()));
		while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
		return s[len]='\0',len;
	}
}
using namespace IO;

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

cs int N=1e5+5;

char s[N];int n;
namespace PAM{
	int son[N][26],fa[N],len[N],last,now;
	int cnt[N],val[N],half[N];
	
	inline void init(){
		while(now!=-1){
			memset(son[now],0,sizeof son[now]);
			fa[now]=len[now]=cnt[now]=val[now]=half[now]=0;
			--now;
		}
		last=0;now=1;
		fa[0]=fa[1]=1;len[1]=-1;
	}
	inline void push_back(char c,int i){c-='a';
		int p=last;
		while(s[i]!=s[i-len[p]-1])p=fa[p];
		if(!son[p][c]){
			len[++now]=len[p]+2;
			int k=fa[p];
			while(s[i]!=s[i-len[k]-1])k=fa[k];
			fa[now]=son[k][c];
			son[p][c]=now;
			k=half[p];
			while(s[i]!=s[i-len[k]-1])k=fa[k];
			k=son[k][c];
			while(len[k]>(len[now]>>1))k=fa[k];
			val[now]=len[k]>0&&len[k]==(len[now]>>1)?val[k]+1:1;
			half[now]=k;
		}
		last=son[p][c];
		++cnt[last];
	}
	
	inline void calc(){
		ll res=0;
		for(int re i=now;i>1;--i)cnt[fa[i]]+=cnt[i],res+=(ll)cnt[i]*val[i];
		cout<<res<<"\n";
	}
}

signed main(){
//	freopen("palprob.in","r",stdin);//freopen("palprob.out","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--){
		PAM::init();
		n=get_s(s+1);
		for(int re i=1;i<=n;++i)PAM::push_back(s[i],i);
		PAM::calc();
	}
	return 0;
}

标签:cnt,val,Palindromeness,CodeChef,len,char,PALPROB,now,define
来源: https://blog.csdn.net/zxyoi_dreamer/article/details/96483516