hdu 6599 I Love Palindrome String 回文自动机

hdu 6599 I Love Palindrome String 回文自动机

当个回文自动机的模板

题意

给一个串S,求长度为i的“特殊回文串”个数,“特殊回文串”要求是回文串,并且自己的一半也是回文串。

思路

求回文串个数相关,优先考虑使用回文自动机,“特殊回文串”要求是回文串,并且自己的一半也是回文串,显然就是fail树扒出来dfs搞一下,记录dfs路径上有没有长度一半的回文串即可。
PS:因为fail指针的意义是最长后缀回文,反过来路径显然是当前节点的回文后缀。

代码

#pragma comment (linker,"/STACK:102400000,102400000")
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define PB push_back
#define LL long long
#define pii pair<int,int>
#define MEM(x,y) memset(x,y,sizeof(x))
#define bug(x) cout<<"debug "#x" is "<<x<<endl;
#define FIO ios::sync_with_stdio(false);
#define ALL(x) x.begin(),x.end()

class PA {//回文自动机
    private:
    //fail 指针指向最长后缀回文状态,可以构建树
    struct Node {
        int len,cnt,ptr[26], fail;  //必要时候 ptr 改成 map
        Node(int len = 0) :cnt(0), len(len), fail(0) { memset(ptr, 0, sizeof(ptr)); }
    };
    vector<Node> nd;
    vector<int> idx;
    int cur;  //当前指针停留的位置,即最后插入字符所对应的节点
    string s;
    int getfail(int x){
        //沿着fail指针找到最长回文后缀(暴力)
        while (s[s.size()-1-nd[x].len-1] != s[s.size()-1]) x = nd[x].fail;
        return x;
    }
    void get_count(){//父亲统计cnt的时候加上儿子的
    for(int i=nd.size()-1;i>=2;i--)
        nd[nd[i].fail].cnt+=nd[i].cnt;
    }
    public:
    PA() :  cur(0){
        nd.PB(Node(0));
        nd[nd.size()-1].fail = 1;
        nd.PB(Node(-1));
        nd[nd.size()-1].fail = 0;
        s="$";
    }
    void extend(char c) {
        s += c;
        int now = getfail(cur);  //找到插入的位置
        if (!nd[now].ptr[c - 'a']){
        //若没有这个节点,则新建并求出它的fail指针
          nd.PB(Node(nd[now].len + 2));
          nd[nd.size()-1].fail = nd[getfail(nd[now].fail)].ptr[c - 'a'];  //新节点的失败指针指向回文后缀
          nd[now].ptr[c - 'a'] = nd.size()-1;   //
        }
        cur = nd[now].ptr[c - 'a'];
        idx.PB(cur);
        ++nd[cur].cnt;
    }
    int get_l(int x){//以x为右端点的最长回文子串的左端点
        return x-nd[idx[x]].len+1;
    }

    void dfs(int x,vector<int> &ans,vector<vector<int>> &E,vector<int> &len,vector<int> &ok){
        if(nd[x].len!=-1)len[nd[x].len]=1;
        if(len[(nd[x].len+1)/2]) ok[x]=1;
        for(int c:E[x])if(c!=0)dfs(c,ans,E,len,ok);
        if(nd[x].len!=-1)len[nd[x].len]=0;
    }
    void addedge(int u,int v,vector<vector<int>> &E){E[u].PB(v);};
    void get_ans(int n){
        vector<int> ans(n+1,0);
        vector<int> len(n+1,0);
        vector<int> ok(nd.size(),0);
        vector<vector<int>> E(nd.size());
        for(int i=0;i<nd.size();i++)addedge(nd[i].fail,i,E);
        dfs(0,ans,E,len,ok);
        get_count();
        for(int i=nd.size()-1;i>=2;i--)if(ok[i])ans[nd[i].len]+=nd[i].cnt;
        for(int i=1;i<=n;i++) cout<<ans[i]<<" \n"[i==n];
    }

};

int main(){
    FIO;
    string s;
    while(cin>>s){
        PA A;
        for(char c:s) A.extend(c);
        A.get_ans(s.size());
    }
    return 0;
}

posted @ 2019-09-27 20:19  zhangxianlong  阅读(167)  评论(0编辑  收藏  举报