HDU - 5157 :Harry and magic string (回文树)

Sample Input

aca
aaaa
Sample Output
3
15
 

题意: 多组输入,每次给定字符串S(|S|<1e5),求多少对不相交的回文串。

思路:可以用回文树求出以每个位置结尾的回文串数,那么累加得到前缀和; 倒着再做一遍得到每个位置为开头的回文串数,乘正向求出的前缀和即可。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep2(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int maxn=100010;
struct PAT
{
    struct node{
        int len,num,fail,son[26];
    }t[maxn];
    int last,n,tot,s[maxn];
    void init()
    {
        memset(t,0,sizeof(t));
        tot=last=1; n=0;
        t[0].len=0; t[1].len=-1;
        t[0].fail=t[1].fail=1;
        s[0]=-1;
    }
    int add(int c){
        int p=last; s[++n]=c;
        while(s[n]!=s[n-1-t[p].len]) p=t[p].fail;
        if(!t[p].son[c]){
            int v=++tot,k=t[p].fail;
            while(s[n]!=s[n-t[k].len-1]) k=t[k].fail;
            t[v].fail=t[k].son[c];
            t[v].len=t[p].len+2;
            t[v].num=t[t[v].fail].num+1;
            t[p].son[c]=v;
        }
        last=t[p].son[c];
        return t[last].num;
    }
}T;
ll ans,sum[maxn];char c[maxn];
int main()
{
    while(~scanf("%s",c+1)){
        int N=strlen(c+1);
        T.init(); ans=0;
        rep(i,1,N) sum[i]=sum[i-1]+T.add(c[i]-'a');
        T.init();
        rep2(i,N,1) ans+=sum[i-1]*T.add(c[i]-'a');
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hua-dong/p/10355921.html