题意
Problem Description
You are given a string S=s1s2…s|S| containing only lowercase English letters. For each integer i∈[1,|S|] , please output how many substrings slsl+1…sr satisfy the following conditions:
∙ r−l+1 equals to i.
∙ The substring slsl+1…sr is a palindrome string.
∙ slsl+1…s⌊(l+r)/2⌋ is a palindrome string too.
|S| denotes the length of string S.
A palindrome string is a sequence of characters which reads the same backward as forward, such as madam or racecar or abba.
Input
There are multiple test cases.
Each case starts with a line containing a string S(1≤|S|≤3×105) containing only lowercase English letters.
It is guaranteed that the sum of |S| in all test cases is no larger than 4×106.
Output
For each test case, output one line containing |S| integers. Any two adjacent integers are separated by a space.
Sample Input
abababa
Sample Output
7 0 0 0 3 0 0
分析
这个统计回文数量的题,就想到了回文树,利用fail来统计答案
对于串的前半段还需要回文,我们对于回文自动机上的一个点代表的串,记录一个位置另外用manacher判断就行
(一开始其实直接倍增跳fail,但是又是WA又是TLE,最后还是没能过)
代码
#include <bits/stdc++.h>
#define ll long long
#define N 300002
using namespace std;
char ss[N],s[N<<1];
int rad[N<<1]; int pp,mx,len,l;
struct PAM
{
int g[N][27],len[N],fail[N],siz[N],last,tot,n,ed[N];
PAM(){tot=0;}
void init()
{
for(int i=0;i<=tot;i++) for(int j=1;j<=26;j++) g[i][j] = 0;
for(int i=0;i<=tot;i++) len[i] = fail[i] = siz[i] = ed[i] = 0;
n = 0; last = 0; tot = 1; fail[1] = fail[0] = 1; len[1] = -1; len[0] = 0;
}
void ins(int nx)
{
n++; int p = last;
while(ss[n-len[p]-1] != ss[n]) p = fail[p];
if(!g[p][nx])
{
int np = ++tot; len[np] = len[p] + 2;
int q = fail[p];
while(ss[n-len[q]-1] != ss[n]) q = fail[q];
fail[np] = g[q][nx]; g[p][nx] = np;
}p=g[p][nx]; last=p; siz[p]++; ed[p] = n;
}
}p;
int cnt[N];
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
while(scanf("%s",ss+1)!=EOF)
{
len = strlen(ss+1); l = len;
p.init();
for(int i=1;i<=l;i++)
p.ins(ss[i]-'a'+1);
for(int i=p.tot;i>=1;i--) p.siz[p.fail[i]] += p.siz[i];
s[0] = '#'; for(int i=1;i<=len;i++) s[(i<<1)-1] = '*' , s[i<<1] = ss[i]; s[(len<<1)+1] = '*'; s[(len<<1)+2] = '$'; len = (len<<1) + 2;
pp=1; mx=0; for(int i=1;i<=len;i++) rad[i] = 0;
for(int i=1;i<=len;i++)
{
if(mx > i) rad[i] = min(rad[(pp<<1)-i],mx-i+1);
while(s[i+rad[i]] == s[i-rad[i]]) rad[i]++;
if(mx < i+rad[i]-1){mx = i+rad[i]-1; pp=i;}
}
for(int i=1;i<=l;i++) cnt[i] = 0;
for(int i=p.tot;i>=1;i--)
{
int l = p.ed[i] - p.len[i] + 1; int r = p.ed[i];
int mid = (l+r)>>1; int x =( (l<<1) + (mid<<1) ) >> 1;
// printf("%intd %intd %intd %intd\n",l,r,p.siz[i],x);
if(rad[x] - 1 >= mid-l+1) cnt[p.len[i]]+=p.siz[i];
}
for(int i=1;i<=l;i++) printf("%d%c",cnt[i]," \n"[i==l]);
}
return 0;
}