【CodeChef PALPROB】Palindromeness(回文自动机)
作者:互联网
传送门
题解:
建立回文自动机,维护每个点right集合大小。
然后维护half指针,表示fail树上第一个长度小于等于自己的一半的回文后缀。
在建立的时候暴力跳祖先的half更新答案,复杂度还是由均摊分析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