HDU6599 I Love Palindrome String(回文树)

 

/*
 * hdu6599
 * 题意:
 * 判断长度从1到len的子串中有多少回文串,且前一半也为回文
 * 题解;
 * 用回文树求出本质不同的回文串,对每个回文串的前一半再判断是否为回文
 */
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ll;
const int maxn=3e5+100;
int a[maxn];
ll f[maxn];
ll p[maxn];
ll cal (int l,int r) {
    if (l==0) return f[r];
    return f[r]-f[l-1]*p[r-l+1];
}
bool check (int l,int r) {
    int mid=(l+r)>>1;
    if ((r-l+1)&1)
        return cal(l,mid)==cal(mid,r);
    else
        return cal(l,mid)==cal(mid+1,r);
    //分别判断
}
struct palin_Tree {
    //回文树
    int nxt[maxn][26];
    int fail[maxn];
    int len[maxn];
    int cnt[maxn];
    int S[maxn];
    int ind[maxn];
    int last,id,n;
    /*
     * 一个节点一个本质不同的回文串
     * len[i]表示回文串i的长度
     * nxt[i][c]表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号
     * cnt[i]表示节点i表示的本质不同的串的个数
     * fail[i]表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串
     * last表示新添加一个字母后形成的最长回文串表示的节点
     * S[i]表示第i次添加的字符
     * ind[i]表示第i号节点是插入到第ind[i]号字符串产生的节点
     */
    int newNode (int x) {
        for (int i=0;i<26;i++)
            nxt[id][i]=0;
        cnt[id]=0;
        len[id]=x;
        return id++;
    }
    void init () {
        id=0;
        newNode(0);
        newNode(-1);
        fail[0]=1;
        S[0]=-1;
        last=n=0;
    }
    int getfail (int x) {
        while (S[n-len[x]-1]!=S[n]) x=fail[x];
        return x;
    }
    void insert (int c) {
        c-='a';
        S[++n]=c;
        int cur=getfail(last);
        if (!nxt[cur][c]) {
            int u=newNode(len[cur]+2);
            fail[u]=nxt[getfail(fail[cur])][c];
            nxt[cur][c]=u;
        }
        last=nxt[cur][c];
        cnt[last]++;
        ind[last]=n;
    }
    void getsum () {
        for (int i=id-1;i>=0;i--) cnt[fail[i]]+=cnt[i];
        for (int i=2;i<id;i++)
            if (check(ind[i]-len[i],ind[i]-1))
                a[len[i]]+=cnt[i];
    }
}Palin_Tree;
char s[maxn];
int main () {
    p[0]=1;
    for (int i=1;i<maxn;i++) p[i]=p[i-1]*13331;
    while (~scanf("%s",s)) {
        int len=strlen(s);
        for (int i=0;i<=len;i++) a[i]=0;
        Palin_Tree.init();
        for (int i=0;i<len;i++) Palin_Tree.insert(s[i]);
        f[0]=s[0];
        for (int i=1;i<len;i++)
            f[i]=f[i-1]*13331+s[i];
        Palin_Tree.getsum();
        for (int i=1;i<=len;i++)
            printf("%d%c",a[i]," \n"[i==len]);
    }
}

 

posted @ 2020-05-07 09:50  zlc0405  阅读(147)  评论(0编辑  收藏  举报