📅  最后修改于: 2023-12-03 15:07:17.926000             🧑  作者: Mango
加权字符串是指给定字符串中每个字符附上一个权重,通常由字符本身和其在字符串中出现的位置生成。比如,对于字符串 "banana",可以将其表示为:
b-1 a-1 n-2 a-2 n-3 a-3
其中,"b-1" 表示字符 'b' 在字符串中出现位置为 1。
回文树是一种数据结构,可以用来高效地处理回文串的相关操作。它的节点分为两种类型:虚拟节点和实际节点。回文串对应的实际节点,可以通过虚拟节点向其父节点扩展得到。更多关于回文树的详细说明可以参考 回文树 - AcWing题库。
给定一个长度为n的字符串,首先可以考虑生成它的加权字符串。
将加权字符串插入到回文树中,将会得到一棵由虚拟节点和实际节点构成的树。叶子节点即为字符串的回文后缀,因此用叶子节点数来表示加权字符串为回文的树的答案。
下面是一个 C++ 实现的样例代码:
#include<bits/stdc++.h>
#define ll long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const int N=1e5+100,M=30;
int n;
char s[N];
int las=1,cnt=1,len[N],link[N],next[N][M],pos[N];
ll ans;
int ins(int c,int lst){
if(next[lst][c]&&len[lst]+1==len[next[lst][c]]) return pos[lst]+1;//优化
int cur=++cnt,p=lst; len[cur]=len[lst]+1;
pos[cur]=pos[lst]+1;
while(p&&!next[p][c]){
next[p][c]=cur; p=link[p];
}
if(!p){
link[cur]=1;
}
else{
int q=next[p][c];
if(len[p]+1==len[q]){
link[cur]=q;
}
else{
int clone=++cnt;
len[clone]=len[p]+1;
link[clone]=link[q];
memcpy(next[clone],next[q],sizeof(next[0]));
while(p&&next[p][c]==q){
next[p][c]=clone; p=link[p];
}
link[cur]=link[q]=clone;
}
}
return pos[cur]+1;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%s",s+1); n=strlen(s+1);
for(int i=1;i<=n;i++){
int x=s[i]-'a';
ans+=ins(x,las);
las=next[las][x];
}
printf("%lld\n",ans);
return 0;
}
其中,pos 数组表示该节点所对应的回文后缀在原字符串中的起始位置。