回文树(回文自动机) - URAL 1960 Palindromes and Super Abilities

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
简介:   Palindromes and Super Abilities Problem's Link:  http://acm.timus.ru/problem.aspx?space=1&num=1960   Mean:  给你一个长度为n的字符串S,输出S的各个前缀中回文串的数量。

  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;
}

 

相关实践学习
基于Hologres轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
Linux入门到精通
本套课程是从入门开始的Linux学习课程,适合初学者阅读。由浅入深案例丰富,通俗易懂。主要涉及基础的系统操作以及工作中常用的各种服务软件的应用、部署和优化。即使是零基础的学员,只要能够坚持把所有章节都学完,也一定会受益匪浅。
目录
相关文章
|
5月前
|
算法
Leetcode 313. Super Ugly Number
题目翻译成中文是『超级丑数』,啥叫丑数?丑数就是素因子只有2,3,5的数,7 14 21不是丑数,因为他们都有7这个素数。 这里的超级丑数只是对丑数的一个扩展,超级丑数的素因子不再仅限于2 3 5,而是由题目给定一个素数数组。与朴素丑数算法相比,只是将素因子变了而已,解法还是和朴素丑数一致的。
63 1
|
存储
LeetCode 313. Super Ugly Number
编写一段程序来查找第 n 个超级丑数。 超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。
64 0
LeetCode 313. Super Ugly Number
AtCoder Beginner Contest 225 F.String Cards(dp)
AtCoder Beginner Contest 225 F.String Cards(dp)
73 0
AtCoder Beginner Contest 214 F - Substrings(subsequence DP)
AtCoder Beginner Contest 214 F - Substrings(subsequence DP)
75 0
Say No to Palindromes
题意: 给出一个字符串,长度为n,而且都是又a,b,c三个字符构成的,然后有m个询问 每个询问给出l r,问要想这个区间内不存在回文子串,至少要改多少个字符 结论: 一共会有六种情况
89 0
|
Go
HDOJ/HDU 1087 Super Jumping! Jumping! Jumping!(经典DP~)
HDOJ/HDU 1087 Super Jumping! Jumping! Jumping!(经典DP~)
65 0