题意:多组输入string,判断长度从1 到 len(string)的字串中有 多少 回文串,且前 一半也为回文
解:用回文树求出本质不同的回文串,对每个回文串前一半再判断是否为回文。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
typedef unsigned long long ull;
const int maxn = 300005;
int Ans[maxn];
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const ll mod = 998244353;
ull ha[maxn],pp[maxn];
ull getha(int l,int r){
if(l==0)return ha[r];
return ha[r] - ha[l-1]*pp[r-l+1];
}
bool check(int l,int r){
int len = r-l+1;
int mid = (l+r)>>1;//哈希值相同则字符相同
if(len & 1) return getha(l,mid) == getha(mid,r);
else return getha(l,mid) == getha(mid+1,r);
}
struct PAM{//回文树
int next[maxn][26],fail[maxn],len[maxn],cnt[maxn],S[maxn];
int index[maxn];
// 一个结点一个本质不同的回文串
//len[i] 表示回文串i的长度
// next[i][c]编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号(儿子)。
//cnt[i] 节点i表示的本质不同的串的个数
//(建树时求出的不是完全的,最后重新统计一遍以后才是正确的)。
// fail[i] 节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
//last 新添加一个字母后所形成的最长回文串表示的节点
// S[i] 第i次添加的字符(一开始设S[0] = -1,也可以是任意一个在串S中不会出现的字符)
//2~id-1 添加的结点 n 添加的字符个数
//index[i] 是i号结点是插入到第 index[i] 号字符串产生的结点
//若字符从0开始,index[i]对应 区间[ index[i]-len[i],index[i]-1 ]
int id,n,last;
int newnode(int x){
for(int i=0;i<26;i++){
next[id][i]=0;
}
cnt[id]=0;
len[id]=x;
return id++;
}
void init(){
id=0;
newnode(0);
newnode(-1);
fail[0]=1;
S[0]=-1;
last=n=0;
}
int getfail(int x){
while(S[n-len[x]-1]!=S[n]) x=fail[x];
return x;
}
void Insert(int c){
c-='a';
S[++n]=c;
int cur=getfail(last);
if(!next[cur][c]){
int now=newnode(len[cur]+2);
fail[now]=next[getfail(fail[cur])][c];
next[cur][c]=now;
}
last=next[cur][c];
cnt[last]++; index[last] = n;
}
void getsum(){//自下向上更新
for(int i=id-1;i>=0;i--){
cnt[fail[i]]+=cnt[i];
}
for(int i=2;i<id;i++){
if(check(index[i]-len[i],index[i]-1)){
//字符串从 0 开始
Ans[len[i]]+=cnt[i];
}
}
}
}pam;
char s[maxn];
int main()
{
pp[0] = 1;
for(int i=1;i<maxn;i++){
pp[i] = pp[i-1]*hash1;
}
while(~scanf("%s",s)){
int len = strlen(s);
for(int i=0;i<=len;i++)Ans[i] = 0;
pam.init();
for(int i=0;i<len;i++)
{
pam.Insert(s[i]);
}
ha[0] = s[0];
for(int i=1;i<len;i++){
ha[i] = ha[i-1]*hash1 + s[i];
}
pam.getsum();
for(int i=1;i<=len;i++){
printf("%d%c",Ans[i]," \n"[i==len]);
}
}
return 0;
}