天天看點

2019牛客多校賽 第六場 C Palindrome Mouse (回文樹/回文自動機)

2019牛客多校賽 第六場 C Palindrome Mouse (回文樹/回文自動機)
2019牛客多校賽 第六場 C Palindrome Mouse (回文樹/回文自動機)
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define eps 1e-5
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<"      :   "<<x<<endl
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
 
const int N = 200010;

struct Palindromic_Tree {

    int next[N][26];//next指針,next指針和字典樹類似,指向的串為目前串兩端加上同一個字元構成
    int fail[N];//fail指針,失配後跳轉到fail指針指向的節點
    int cnt[N];//cnt[i]表示以i為結尾的最長的串的個數
    int num[N];//num[i]表示,以i為結尾的回文串的個數
    int len[N];//len[i]表示節點i表示的回文串的長度
    int S[N];//存放添加的字元
    int v[N];
    int t[N];
    int sz[N];
    int last ;//指向上一個字元所在的節點,友善下一次add
    int n ;//字元數組指針
    int p ;//節點指針

    inline int newnode ( int l ) //建立節點
    {
        for ( int i = 0 ; i < 26 ; ++ i ) next[p][i] = 0 ;
        cnt[p] = num[p] = 0 ; len[p] = l ; return p ++ ;
    }

    inline void init () //初始化
    {
        p = 0 ; newnode (  0 ) ; newnode ( -1 ) ;
        last = n = 0 ; S[n] = -1 ;//開頭放一個字元集中沒有的字元,減少特判
        fail[0] = 1 ;
    }

    inline int get_fail ( int x ) //和KMP一樣,失配後找一個盡量最長的
    {
        while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;
        return x ;
    }

    inline void add ( int c ) 
    {
        c -= 'a' ; S[++ n] = c ;
        int cur = get_fail ( last ) ;//通過上一個回文串找這個回文串的比對位置
        if ( !next[cur][c] )  //如果這個回文串沒有出現過,說明出現了一個新的本質不同的回文串
        {
            int now = newnode ( len[cur] + 2 ) ;//建立節點
            fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自動機一樣建立fail指針,以便失配後跳轉
            next[cur][c] = now ;
            num[now] = num[fail[now]] + 1 ;
        }
        last = next[cur][c] ;
        cnt[last] ++ ;
    }

    void dfs(int x)
    {
        t[x]=(v[x]==0)+(v[fail[x]]==0);
        v[x]++; v[fail[x]]++; sz[x]=1;
        for(int i=0;i<26;i++)
        {
            if (next[x][i]==0) continue;
            dfs(next[x][i]);
            sz[x]+=sz[next[x][i]];
        }
        v[x]--; v[fail[x]]--;
    }

    inline LL count()
    {   
        LL res=0;
        dfs(0); dfs(1);
        for(int i=2;i<p;i++)
            res+=sz[i]*t[i]-1;
        return res;
    }
} PAM;

char s[N];

int main(){
    int T,T_T=0;sc(T);
    while(T--)
    {
        PAM.init();
        scanf("%s",s);
        for(int i=0;s[i];i++) PAM.add(s[i]);
        printf("Case #%d: %lld\n",++T_T,PAM.count());
    }
}