📌  相关文章
📜  加权字符串为回文的树的叶子节点数(1)

📅  最后修改于: 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 数组表示该节点所对应的回文后缀在原字符串中的起始位置。