• 回文树(回文自动机)


      Palindromes and Super Abilities

    Problem's Link:  http://acm.timus.ru/problem.aspx?space=1&num=1960


     

    Mean: 

    给你一个长度为n的字符串S,输出S的各个前缀中回文串的数量。

    analyse:

    回文树(回文自动机)的模板题。

    由于回文自动机中的p是一个计数器,也相当于一个指针,记录的是当前插入字符C后回文树中有多少个节点。

    那么我们只需要一路插,一路输出p-2就行。

    p-2是因为一开始回文树中就有两个节点。这是两个根节点,分别是长度为偶数和奇数的回文串的根节点。

     

    Time complexity: O(N)

     

    Source code: 

    /*
    * this code is made by crazyacking
    * Verdict: Accepted
    * Submission Date: 2015-08-17-14.58
    * Time: 0MS
    * Memory: 137KB
    */
    #include <queue>
    #include <cstdio>
    #include <set>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <climits>
    #include <map>
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #define  LL long long
    #define  ULL unsigned long long
    using namespace std;

    const int MAXN = 100005 ;
    const int N = 26 ;
    char s[MAXN];
    namespace Palindromic_Tree
    {
         int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
         int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点
         int cnt[MAXN] ;
         int num[MAXN] ;
         int len[MAXN] ;//len[i]表示节点i表示的回文串的长度
         int S[MAXN] ;//存放添加的字符
         int last ;//指向上一个字符所在的节点,方便下一次add
         int n ;//字符数组指针
         int p ;//节点指针

         int newnode(int l)     //新建节点
         {
               for(int i = 0 ; i < N ; ++ i) next[p][i] = 0 ;
               cnt[p] = 0 ;
               num[p] = 0 ;
               len[p] = l ;
               return p ++ ;
         }

         void init()   //初始化
         {
               p = 0 ;
               newnode(0) ;
               newnode(-1) ;
               last = 0 ;
               n = 0 ;
               S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判
               fail[0] = 1 ;
         }

         int get_fail(int x)     //和KMP一样,失配后找一个尽量最长的
         {
               while(S[n - len[x] - 1] != S[n]) x = fail[x] ;
               return x ;
         }

         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 Count()
         {
               for(int i = p - 1 ; i >= 0 ; -- i) cnt[fail[i]] += cnt[i] ;
               //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
         }
    } ;


    using namespace Palindromic_Tree;

    int main()
    {
         ios_base::sync_with_stdio(false);
         cin.tie(0);
         while(~scanf("%s",s))
         {
               init();
               for(int i=0;s[i];++i)
               {
                     add(s[i]);
                     printf(i==0?"%d":" %d",p-2);
               }
               puts("");
    //            Count();
         }
         return 0;
    }
    /*

    */

    代码2:

    /*
    * this code is made by crazyacking
    * Verdict: Accepted
    * Submission Date: 2015-08-17-16.51
    * Time: 0MS
    * Memory: 137KB
    */
    #include <queue>
    #include <cstdio>
    #include <set>
    #include <string>
    #include <stack>
    #include <cmath>
    #include <climits>
    #include <map>
    #include <cstdlib>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #define  LL long long
    #define  ULL unsigned long long
    using namespace std;

    const int MAXN = 100010;
    struct node
    {
         int next[26];
         int len;
         int sufflink;
         int num;
    };
    int len;
    char s[MAXN];
    node tree[MAXN];
    int num; // node 1 - root with len -1, node 2 - root with len 0
    int suff; // max suffix palindrome
    long long ans;
    bool addLetter(int pos)
    {
         int cur = suff, curlen = 0;
         int let = s[pos] - 'a';
         while(true)
         {
               curlen = tree[cur].len;
               if(pos-1-curlen>=0&&s[pos-1-curlen]==s[pos]) break;
               cur = tree[cur].sufflink;
         }
         if(tree[cur].next[let])
         {
               suff = tree[cur].next[let];
               return false;
         } suff = ++num;
         tree[num].len = tree[cur].len + 2;
         tree[cur].next[let] = num;
         if(tree[num].len == 1)
         {
               tree[num].sufflink = 2;
               tree[num].num = 1;
               return true;
         }
         while(true)
         {
               cur = tree[cur].sufflink;
               curlen = tree[cur].len;
               if(pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos])
               {
                     tree[num].sufflink = tree[cur].next[let];
                     break;
               }
         }
         tree[num].num = 1 + tree[tree[num].sufflink].num;
         return true;
    }
    void initTree()
    {
         num = 2; suff = 2;
         tree[1].len = -1; tree[1].sufflink = 1;
         tree[2].len = 0; tree[2].sufflink = 1;
    }
    int main()
    {
         scanf("%s",s);
         len = strlen(s);
         initTree();
         for(int i = 0; i < len; i++)
         {
               addLetter(i);
               printf(i==0?"%d":" %d",num-2);
    //            ans += tree[suff].num;
         }
         putchar(10);
    //       cout << ans << endl;
         return 0;
    }
  • 相关阅读:
    【ALearning】第三章 Android基本常见控件
    【问题汇总】ListView的FooterView设置可见性的问题
    shell重定向调试信息
    Android提供的系统服务之--TelephonyManager(电话管理器)
    工作一年的总结
    【甘道夫】HBase基本数据操作的详细说明【完整版,精绝】
    未定义标识符_ConnectionPtr
    POJ 1329 三角外接圆
    IOS开发-加载本地音乐
    SQL Server 性能优化3 该指数(Index)保养
  • 原文地址:https://www.cnblogs.com/crazyacking/p/4736871.html
Copyright © 2020-2023  润新知