在网络赛现学回文树。。不过还是赛后出题了。。gg
回文树
概述
回文树是对着一个单串建立的一种处理字符串的数据结构,主要用于计数(回文子串种类及个数)。基本建立思路是建立其前缀的回文树,然后每加上一个字符,统计产生了什么回文。
下图展示了回文树的结构。
对于字符串 abccbab
,我们可以建出以下回文树:
红色箭头表示 fail
指针,蓝色箭头表示字符匹配成功会转移的位置。
回文树可以解决的问题
假设我们有一个串$S$,$S$下标从$0$开始,则回文树能做到如下几点:
1.求串$S$前缀$0 - i$内本质不同回文串的个数(两个串长度不同或者长度相同且至少有一个字符不同便是本质不同)
2.求串$S$内每一个本质不同回文串出现的次数
3.求串$S$内回文串的个数(其实就是$1$和$2$结合起来)
4.求以下标$i$结尾的回文串的个数
回文树的结构
首先我们定义一些变量。
1.len[i]
表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串);
2.ch[i][c]
表示编号为i的节点表示的回文串在两边添加字符c
以后变成的回文串的编号。
3.fail[i]
表示节点i
失配以后跳转到长度小于该串且以该节点表示回文串的最后一个字符结尾的最长回文串表示的节点。
4.ans[i]
表示节点i
表示的本质不同的串的个数(建树时求出的不是完全的,最后count()
函数跑一遍以后才是正确的)
5.num[i]
表示以节点i
表示的最长回文串的最右端点为回文串结尾的回文串个数。
6.last
指向新添加一个字母后所形成的最长回文串表示的节点。
7.S[i]
表示第i
次添加的字符(一开始设S[0] = -1
(可以是任意一个在串S
中不会出现的字符))。
8.p
表示添加的节点个数。
9.cnt
表示添加的字符个数。
回文树模板
|
|
回文树的应用
UOJ 103 Palindromes
(为什么是这个编号。。)
就是这道题提出了这个算法。
出现次数用 ans[i]
,长度用 len[i]
。
|
|
HDU 3948 The Number of Palindromes
求本质不同的回文串的个数。
板子的来源。。
|
|
CodeChef PALPROB Palindromeness
求出当前回文串节点的长度的一半的那个回文串所代表的节点。
定义 half
表示长度最长并且长度小于等于当前节点长度一半的回文串所代表的节点 ,half
的求法,如果当前点的len=1
, half
不存在;否则,从构建回文树时的父亲节点(不是fail
指针)所代表的那个点的half
开始
暴力跳fail
,直到找到满足条件的点,假设是 pos
,当前点的half
就是 trans[pos][当前字符]
。
有毒。。把我的板子改飞了。。
|
|
2018年 南京网络赛 Problem I Skr
求一个数字串中所有本质不同的回文子串之和。
疯狂改板子。。不过还差几分钟就能交了。。
|
|
HDU 5658 CA Loves Palindromic
问任意区间中本质不同的回文串数量。因为长度才1000就暴力枚举区间即可。
|
|
BZOJ 2565 最长双回文串
求最长的位置,这个位置满足:把一个串切成两个串,这两个串都是回文串。
倒着顺着跑两遍 PA 就行了。。。
为什么倒着的时候,要全部遍历,正着的时候就不用遍历头了?
因为要对应位置,见下一题的分析。
|
|
HDU 5157 Harry and magic string
求每个点的前面和后面的本质回文字符串的数量和。
上一道题就没搞清楚位置怎么算,这道题就出事了。。
按照样例2来说:
字符位置 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
字符 | a | a | a | a |
x[i] = 正向建回文树的num[i] |
1 | 2 | 3 | 4 |
y[i] = 逆向建回文树的num[i] |
4 | 3 | 2 | 1 |
sy[i] = y[i] 的后缀和 |
10 | 6 | 3 | 1 |
如果你要算第 0
个字符的数量和的话,从表中可以看出,我们需要计算 x[0] * sy[1]
。这是因为 sy[0]
表示的是从 4
到 0
,就与 x[0]
重复了。
总结成一句话,对于每个点就是 x[i] * sy[i + 1]
。
上一道题与这道题的位置分析是一个道理。
|
|