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;
}

posted @ 2020-11-23 22:11  xyq0220  阅读(51)  评论(0编辑  收藏  举报