Codechef PALPROB Palindromeness 回文树
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codechef PALPROB Palindromeness 回文树相关的知识,希望对你有一定的参考价值。
构建出回文树,那么我们需要对于回文树的每一个节点求出它在原串中的出现次数和前\(\frac{len}{2}\)个字符构成的串
前者可以直接在fail树上传递endpos标记,后者可以倍增。但是后者还有一种复杂度\(O(?)\)的做法跑得非常快:
对于每一个点维护\(half_x\)表示点\(x\)对应的串中\(\leq \frac{len_x}{2}\)的最长的回文后缀在PAM的位置。新插入一个节点时,从它的trans的父亲的half开始,暴力跳fail直到找到当前节点的half。对于长度为\(1\)的节点单独判断一下。
所以上面的做法到底是不是\(O(n)\)的呢……
回文树一会儿不写全部忘光
#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;
const int _ = 1e5 + 7;
char s[_];
namespace PAM{
int trans[_][26] , len[_] , fa[_] , hlf[_] , val[_] , endpos[_];
int cnt , lst;
#define clr(x) memset(x , 0 , sizeof(x));
void init(){
cnt = 1; lst = 0;
clr(trans); clr(len); clr(fa); clr(hlf);
clr(val); clr(endpos);
fa[1] = fa[0] = 1; len[1] = -1;
}
void extend(int pos){
int p = lst;
while(s[pos] != s[pos - len[p] - 1]) p = fa[p];
if(trans[p][s[pos] - 'a']){
lst = trans[p][s[pos] - 'a']; ++endpos[lst];
return;
}
int k = ++cnt , q = fa[p];
while(s[pos] != s[pos - len[q] - 1]) q = fa[q];
fa[k] = trans[q][s[pos] - 'a']; trans[p][s[pos] - 'a'] = k;
len[k] = len[p] + 2; lst = k; ++endpos[lst];
if(len[k] <= 1) val[hlf[k] = k] = 1;
else{
p = hlf[p];
while(s[pos - len[p] - 1] != s[pos] || len[p] + 2 > len[k] / 2)
p = fa[p];
hlf[k] = trans[p][s[pos] - 'a'];
val[k] = 1 + (len[hlf[k]] == len[k] / 2 ? val[hlf[k]] : 0);
}
}
long long calc(){
for(int i = cnt ; i >= 1 ; --i)
endpos[fa[i]] += endpos[i];
long long ans = 0;
for(int i = 2 ; i <= cnt ; ++i)
ans += 1ll * val[i] * endpos[i];
return ans;
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
int T;
for(scanf("%d" , &T) ; T ; --T){
scanf("%s" , s + 1); int L = strlen(s + 1);
PAM::init();
for(int i = 1 ; i <= L ; ++i)
PAM::extend(i);
cout << PAM::calc() << endl;
}
return 0;
}
以上是关于Codechef PALPROB Palindromeness 回文树的主要内容,如果未能解决你的问题,请参考以下文章