题目
思路:先建好一棵回文树,然后问题就是如何快速判断一个结点代表的回文串是不是题目要求的回文串,暴力判断就是顺着后缀链接找,然后就T了 emmm。而实际上在插入一个结点时,这个代表的回文串我们可以通过它的长度和现在插入到第几个字符这两个信息判断出它的起始位置,起始 l 知道,末尾 r 知道,长度为len,如果要满足题设要求,即[l,l+(len+1)/2]这个区间的子串也应该是回文串,在这里有个性质:如果[l,r]是回文串 且 [l,l+(len+1)/2]这个子串等于[r-(len+1)/2 + 1,r]代表的子串,那么这两个子串都是回文串,说明见图:x代表是某个字符,相同颜色线连接的字符相等;这样顺着线找 就会发现前三个字符是回文串
所以用这个性质+hash就可以O(1)地判断这个结点代表的字符串是否满足要求。
还有个我想吐得点就是:hash的时候如果base取大了,比如200就WA
,想不懂,取小了WA还能理解,取大了也能WA就觉得离谱。,。,
#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#include<cstring>
#include<queue>
const int maxn = 3e5 + 10;
const int maxm = 1e6 + 10;
const int inf_max = 0x3f3f3f;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
char str[maxn];
int ans[maxn];
const ull base = 131;
ull fac[maxn],hs[maxn];
ull gethash(int l, int r){
return hs[r] - hs[l - 1] * fac[r - l + 1];
}
struct HW {
struct node {
int len,cnt,ch[26],fail,satisfy;
}tree[maxn];
int tot,chnum,last;
char exsitch[maxn];
int newnode(int len) {
int cur = ++tot;
memset(tree[cur].ch,0,sizeof(tree[cur].ch));
tree[cur].cnt = tree[cur].fail = tree[cur].satisfy = 0;tree[cur].len = len;
return cur;
}
void Initial() {
tot = -1;
newnode(0);newnode(-1);
tree[0].fail = 1;
exsitch[chnum = last = 0] = '$';
}
int getfail(int x) {
while(exsitch[chnum] != exsitch[chnum - tree[x].len - 1]) x = tree[x].fail;
return x;
}
void ins(int x) {
int id = x - 'a';
exsitch[++chnum] = x;
int now = getfail(last);
if(!tree[now].ch[id]) {
int cur = newnode(tree[now].len + 2);
tree[cur].fail = tree[getfail(tree[now].fail)].ch[id];
tree[now].ch[id] = cur;
int half = (tree[cur].len + 1) / 2;
if(tree[cur].len == 1 || gethash(chnum - tree[cur].len + 1, chnum - tree[cur].len + half) == gethash(chnum - half + 1, chnum)) tree[cur].satisfy = 1;
else tree[cur].satisfy = 0;
}
last = tree[now].ch[id];
tree[last].cnt++;
}
void solve() {
for(int i = tot;i >= 0; --i) {
int f = tree[i].fail,len = tree[i].len;
tree[f].cnt += tree[i].cnt;
if(tree[i].satisfy) ans[len] += tree[i].cnt;
}
}
}hwauto;
int main()
{
fac[0] = 1;
for(int i = 1;i <= 300005; ++i) fac[i] = fac[i - 1] * base;
while(~scanf("%s",str + 1)) {
memset(ans,0,sizeof(ans));
int len = strlen(str + 1);
hwauto.Initial();
hs[0] = 0;
for(int i = 1;i <= len; ++i) hs[i] = hs[i-1] * base + str[i];
for(int i = 1;i <= len; ++i) hwauto.ins(str[i]);
hwauto.solve();
for(int i = 1;i <= len; ++i) {
printf("%d%c",ans[i],i == len ? '\n' : ' ');
}
}
return 0;
}