2019徐州网络赛G. Colorful String【回文树】

传送门

题意

定义一个字符串的值为字符串中不同字符的种数,求一个字符串的所有回文子串的值的和。

题解

算是回文自动机的板子题,可惜之前做的时候没学,直接构建回文树,dfs统计就行了。
写这个还是为了完善一下回文自动机的模板,之前写的那个模板不好用。

代码

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N=3e5+10;
char s[N];
int n;
LL ans;
struct PAM{
    int tr[N][26],fail[N],len[N],cnt[N],tot,last,n;
    int getfail(int x){
        while(s[n]!=s[n-len[x]-1]) x=fail[x];
        return x;
    }
    void init(char *s){
        n=tot=last=0;
        cnt[0]=len[0]=cnt[1]=0;
        memset(tr[0],0,sizeof(tr[0]));
        memset(tr[1],0,sizeof(tr[1]));
        fail[0]=1;
        len[++tot]=-1;
        for(n=1;s[n]!='\0';n++){
            int c=s[n]-'a',cur=getfail(last);
            if(!tr[cur][c]){
                len[++tot]=len[cur]+2;cnt[tot]=0;
                memset(tr[tot],0,sizeof(tr[tot]));
                fail[tot]=tr[getfail(fail[cur])][c];
                tr[cur][c]=tot;
            }
            last=tr[cur][c];
            cnt[last]++;
        }
        for(int i=tot;i>=0;i--) cnt[fail[i]]+=cnt[i];
    }
    int count,vis[26];
    void dfs(int u){
        ans+=count*cnt[u];
        for(int i=0;i<26;i++){
            if(!tr[u][i]) continue;
            vis[i]++;if(vis[i]==1) count++;
            dfs(tr[u][i]);
            vis[i]--;if(!vis[i]) count--;
        }
    }
}pam;


int main(){
    scanf("%s",s+1);
    pam.init(s);
    pam.dfs(0);
    pam.dfs(1);
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12529732.html