zoukankan      html  css  js  c++  java
  • 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]<<" 
    "[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;
    }
    
    
  • 相关阅读:
    LD_DEBUG
    kernel相关前沿技术了解
    awk一次性分别赋值多个value给多个变量,速度对比
    google spanner
    python指定日期后加几天判断
    awk手册
    2017.12.28 现货黄金止盈复盘
    数据库和struts2的拦截器
    类和数据库的扫盲
    深入理解SQL的四种连接-左外连接、右外连接、内连接、全连接(经典)
  • 原文地址:https://www.cnblogs.com/zhangxianlong/p/11600157.html
Copyright © 2011-2022 走看看