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

转载于:https://www.cnblogs.com/crazyacking/p/4736871.html

回文树(回文自动机) - URAL 1960 Palindromes and Super Abilities相关推荐

  1. 回文树/回文自动机 引入

    回文树/回文自动机引入 在介绍这种数据结构之前,我们来回顾一下处理字符串的一些武器: 1.KMP.AC自动机 2.后缀三姐妹(后缀树,后缀数组,后缀自动机) 3.字符串hash 4.字符串dp 5.m ...

  2. 「学习笔记」回文树/回文自动机(Palindromic Tree)

    引入 有时候题目要求一些这样的问题 1. 求以串 s s s 本质不同的回文串个数(即长度不同或长度相同且至少有一个字符不相同的字符串) 2. 求以位置i" role="prese ...

  3. 回文树/回文自动机学习

    len[i]:节点i的回文串的长度 next[i][c]:节点i的回文串在两边添加字符c以后变成的回文串的编号 fail[i]:指向i的最长回文后缀且不为i cnt[i]:节点i表示的回文串在S中出现 ...

  4. 哦也!伟大的回文树(回文自动机)!

    例题引入 例题引入:洛谷P3649 话说马上就要APIO了,litble去看了看历年的APIO题--发现这道题用回文树非常好做,所以就去学了一下回文树. 所谓回文树,就是每个节点代表一个不同的回文串的 ...

  5. 论如何优雅的处理回文串 - 回文自动机详解

    写在前面 最近无意中看到了这个数据结构,顺便也就学习了一下. 而且发现网上关于这个算法的描述有很多地方是错的,在这里做了一些更正. 处理字符串的算法很多: KMP,E-KMP,AC自动机,后缀三兄弟: ...

  6. Palindromic Tree——回文树【处理一类回文串问题的强力工具】

    今天我们来学习一个神奇的数据结构:Palindromic Tree.中译过来就是--回文树. 那么这个回文树有何功能? 假设我们有一个串S,S下标从0开始,则回文树能做到如下几点: 1.求串S前缀0~ ...

  7. 回文树介绍(Palindromic Tree)

    简介 回文树是由Mikhail Rubinchik大神发明的,在Petrozavodsk Summer Camp 2014上首次提出来,是一个很新的数据结构,目前相关资料比较少. 顾名思义,回文树是一 ...

  8. 回文树或者回文自动机,及相关例题

    回文树简述 在大部分说法中,回文树与回文自动机指的是一个东西: 回文树是对一个字符串,基于自动机思想构建的处理回文问题的树形结构: 回文树是对着一个单串建立的: 于是他主要用于计数(回文子串种类及个数 ...

  9. BZOJ2565 最长双回文子串 回文自动机,回文树

    bzoj2565: 最长双回文串 题意 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为"abc",逆序为"cba" ...

最新文章

  1. 当代新青年,在看什么书?|主题书单揭晓
  2. sed、grep、awk
  3. mysql表分区和表空间_mysql分表和分区的区别浅析
  4. 西门子标准报文1常用_基于Snap7使用C#编程访问西门子PLC系列教程(2)-S7协议
  5. C++ STL:unordered_map::begin()函数不一定返回第一个元素
  6. 苹果更新未知错误17_iOS 13 新功能,静音未知来电
  7. CVE-2017-10271 WebLogic XMLDecoder反序列化漏洞
  8. timeshift备份你的Linux系统
  9. 2018.09.19python学习第七天part1
  10. HBase架构设计及原理分析
  11. ActiveMQ消息的持久化策略
  12. 计算机硬件基础课设总结,计算机硬件基础课程设计报告.doc
  13. android build.gradle的repositories设置
  14. python resample_Python骚操作:利用Python获取摄像头并实时控制人脸!
  15. 让DB2跑得更快——DB2内部解析与性能优化
  16. 统计表中有无数据并发送邮件
  17. mysql中的utf-8_永远不要在MySQL中使用UTF-8
  18. LoadRunner 常用函数大全+1
  19. 2021腾讯犀牛鸟校园布道师养成计划丨百校同行
  20. 企业管理不可忽视“工作日志”

热门文章

  1. LeetCode算法题8:递归和回溯1
  2. 购买阿里云服务器地域如何选择?
  3. Mysql源码学习——源码目录结构
  4. Ubuntu安装设置nginx和nohup常用操作
  5. 起底车载互联市场:产业市场庞大,但产品鱼龙混杂
  6. Keepalived+nginx造成流量异常
  7. [RabbitMQ]RabbitMQ原理与相关操作(一)
  8. 基于clang插件的一种iOS包大小瘦身方案
  9. ElasticSearch 2.0以后的改动导致旧的资料和书籍需要订正的部分
  10. 相识、相恋、相伴【与51CTO的故事】