天天看点

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());
    }
}