CodeChef Palindromeness 回文自动机
CodeChef Palindromeness
题意
定义一个字符串\(S\)的回文指数为\(f(S)\)
\[\begin{equation}
f(S)=
\begin{cases}
0&\mbox{if $S$ is not a palindrome}\\
1&\mbox{if $S$ is a palindrome and |S|=1} \\
1+f(\mbox{first}~\lfloor \frac{|S|}{2} \rfloor~\mbox{symbols of S})&\mbox{if $S$ is a palindrome and |S|>1}
\end{cases}
\end{equation}
\]
给定一个字符串\(S\),求它的所有子串的回文指数。
\(|S| \le 10^5\)
分析
回文自动机统计每个回文子串的出现次数,并求出\(trans\)指针,对每个回文子串跳\(trans\)指针统计答案即可。
Code
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=5e5+10;
char s[maxn];
int T,n,now;
struct PAM{
int son[maxn][26],fail[maxn],len[maxn],cnt[maxn],trans[maxn],tot,last;
int newnode(int x){
++tot;
for(int i=0;i<26;i++) son[tot][i]=0;
fail[tot]=0;len[tot]=x;cnt[tot]=0;
return tot;
}
void init(){
tot=-1;newnode(0);newnode(-1);
fail[0]=1;
last=0;
}
int gao(int x){
while(s[now-len[x]-1]!=s[now]) x=fail[x];
return x;
}
void insert(){
int p=gao(last);
if(!son[p][s[now]-'a']){
int tmp=son[gao(fail[p])][s[now]-'a'];
son[p][s[now]-'a']=newnode(len[p]+2);
fail[tot]=tmp;
if(len[tot]<=2) trans[tot]=fail[tot];
else{
tmp=trans[p];
while(s[now-len[tmp]-1]!=s[now]||(len[tmp]+2)*2>len[tot]) tmp=fail[tmp];
trans[tot]=son[tmp][s[now]-'a'];
}
}
last=son[p][s[now]-'a'];
cnt[last]++;
}
ll qy(){
for(int i=tot;i>=1;i--) cnt[fail[i]]+=cnt[i];
ll ans=0;
for(int i=1;i<=tot;i++){
int x=i;
while(len[x]){
ans+=cnt[i];
int y=trans[x];
if(len[y]!=len[x]/2) break;
x=y;
}
}
return ans;
}
}P;
int main(){
scanf("%d",&T);
while(T--){
scanf("%s",s+1);
n=strlen(s+1);
P.init();
for(now=1;now<=n;now++){
P.insert();
}
printf("%lld\n",P.qy());
}
return 0;
}