Palindromeness CodeChef

传送门

分析

有中文题面所以就不写题目大意了

我们先建出回文树

然后根据fail信息建出一棵树

从根向下dfs,中间记录每一个len出现在哪个节点即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int n,fail[300100],son[300100][30],sum[300100],len[300100],cnt,last;
int val[300100],pos[300100],nxt[300100],head[300100],to[300100],tot;
long long Ans;
char s[300100];
inline void add(int x,int y){nxt[++tot]=head[x];head[x]=tot;to[tot]=y;}
inline void new_node(int x){len[++cnt]=x;sum[cnt]=0;}
inline int get_fail(int x,int n){while(s[n]!=s[n-len[x]-1])x=fail[x];return x;}
inline void build(){
    for(int i=1;i<=n;i++){
      int x=s[i]-'a',now=get_fail(last,i);
      if(!son[now][x]){
          new_node(len[now]+2);
          fail[cnt]=son[get_fail(fail[now],i)][x];
          son[now][x]=cnt;
      }
      last=son[now][x];
      sum[last]++;
    }
}
inline void dfs(int x){
    if(x>1)pos[len[x]]=x,Ans+=(long long)(val[x]=val[pos[len[x]/2]]+1)*sum[x];
    for(int i=head[x];i;i=nxt[i])dfs(to[i]);
    if(x>1)pos[len[x]]=0;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
      scanf("%s",s+1);
      n=strlen(s+1);
      memset(sum,0,sizeof(sum));
      memset(son,0,sizeof(son));
      memset(fail,0,sizeof(fail));
      memset(len,0,sizeof(len));
      memset(head,0,sizeof(head));
      tot=0;
      Ans=0;
      cnt=-1;
      new_node(0),new_node(-1);
      fail[1]=fail[0]=1;
      last=0;
      build();
      add(1,0);
      for(int i=cnt;i>1;i--)sum[fail[i]]+=sum[i],add(fail[i],i);
      dfs(1);
      printf("%lld
",Ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/10406353.html