題目
思路:先建好一棵迴文樹,然後問題就是如何快速判斷一個結點代表的迴文串是不是題目要求的迴文串,暴力判斷就是順着後綴鏈接找,然後就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;
}