Codechef Palindromeness 和 SHOI2011 双倍回文
Palindromeness
Let us define the palindromeness of a string in the following way:
- If the string is not a palindrome, its' palindromeness is zero.
- The palindromeness of an one-letter string is 1.
- The palindromness of a string S of the length greater than one is 1 + "palindromeness of the string that is formed by the first [|S|/2] symbols of S".
You are given a string S. Find the sum of the palindromenesses of all the non empty substrings of S (i.e. S[i..j], where i <= j). In other words, you have to calculate the sum of palindromenesses of N * (N + 1) / 2 substrings of S, where N is the length of S.
- 1 ≤ |S| ≤ 105。
题解
翁文涛《回文树及其应用》。
\(len_i=1\) 时特殊处理 \(half_i=even\)。
CO int N=100000+10;
namespace PAM{
int str[N],n;
int last,tot;
int ch[N][26],fa[N],len[N];
int half[N],val[N],siz[N];
void init(){
memset(str,-1,sizeof str),n=0;
last=tot=1;
memset(ch,0,sizeof ch);
fa[0]=fa[1]=1,len[0]=0,len[1]=-1;
memset(siz,0,sizeof siz);
}
int get_fail(int x){
while(str[n-len[x]-1]!=str[n]) x=fa[x];
return x;
}
void extend(int c){
int p=get_fail(last);
if(!ch[p][c]){
int cur=++tot;
len[cur]=len[p]+2;
fa[cur]=ch[get_fail(fa[p])][c];
ch[p][c]=cur;
if(len[cur]==1) half[cur]=0;
else{
int q=half[p];
while(str[n-len[q]-1]!=str[n] or
2*(len[q]+2)>len[cur]) q=fa[q];
half[cur]=ch[q][c];
}
val[cur]=1+(len[cur]/2==len[half[cur]]?val[half[cur]]:0);
}
last=ch[p][c];
++siz[last];
}
LL main(){
for(int i=tot;i>=2;--i) siz[fa[i]]+=siz[i];
LL ans=0;
for(int i=tot;i>=2;--i) ans+=(LL)siz[i]*val[i];
return ans;
}
}
char str[N];
void real_main(){
scanf("%s",str+1);
int n=strlen(str+1);
PAM::init();
for(int i=1;i<=n;++i){
PAM::str[++PAM::n]=str[i]-'a';
PAM::extend(str[i]-'a');
}
printf("%lld\n",PAM::main());
}
int main(){
for(int T=read<int>();T--;) real_main();
return 0;
}
双倍回文
如果 s 能够写成 wwRwwR 的形式,则称 s 是双倍回文。
s 的长度是 4 的倍数,前后两半都是相同的回文。
对于给定的字符串,计算它的最长双倍回文串的长度。
N<=500000
yyb的题解
发现这个长度为自身一半的的回文串是可以方便地转移的。
对于每个节点,我们维护一个half来表示长度最长的、不超过它长度一半的那个祖先节点
这样子只需要判断一下当前点的half长度是否是一半,并且当前串的长度是四的倍数就好了
找 half 就用 p 的 half 来跳就行了。
co int N=500000+10;
char s[N];
int last=1,tot=1;
int ch[N][26],fa[N]={1,1},len[N]={0,-1},half[N];
int get_fa(int x,int i){
while(s[i-len[x]-1]!=s[i]) x=fa[x];
return x;
}
void extend(int i){
int p=get_fa(last,i);
int x=ch[p][s[i]-'a'];
if(!x){
x=++tot;
fa[x]=ch[get_fa(fa[p],i)][s[i]-'a'];
len[x]=len[p]+2;
ch[p][s[i]-'a']=x;
if(len[x]==1) half[x]=0;
else{
int q=half[p];
while(s[i-len[q]-1]!=s[i]||(len[q]+2)<<1>len[x]) q=fa[q];
half[x]=ch[q][s[i]-'a'];
}
}
last=x;
}
int main(){
int n=read<int>();
scanf("%s",s+1);
for(int i=1;i<=n;++i) extend(i);
int ans=0;
for(int i=1;i<=tot;++i)
if(len[half[i]]<<1==len[i]&&len[i]%4==0)
ans=max(ans,len[i]);
printf("%d\n",ans);
return 0;
}
静渊以有谋,疏通而知事。