【距离GDOI:131天】 后缀数组完毕
用了近两周的时间,终于把罗神那篇后缀数组应用看完了,题目也写了一遍,T了无数次...详见前几篇博文...
后缀数组很重要的是那个height数组,可以用来做各种奇奇怪怪的东西...常用方法去是去二分,比较少见的是单调栈维护...明天把切的12道题题型整理归纳后再补在后面吧,有点晚了...明天复习AC自动机去!
预备:最长公共前缀
对于suffix(i)和suffix(j) 假设rank[i]<rank[j] 那么lcp(i,j)=min{height[k]| rank[i]+1<=k<=rank[j]}
一、分组+二分长度:
1.不可重叠最长重复子串 (poj1743)
二分长度k,将heigh[i]>=k的分为一组..然后对于这组后缀,我们记录其sa[i]的最大值和最小值,若最大值与最小值之差不小于k,那么长度k成立..
2.可重叠的 k 次最长重复子串(poj3261)
同上一道题,二分长度,判断一组的后缀个数不少于k即可..
3.不小于 k 个字符串中的最长子串(poj3294)
二分长度,分组。分组中判断k个:将字符串染色,然后用布尔数组判断是否出现在多个字符串即可...
4.每个字符串至少出现两次且不重叠的最长子串(spoj220)
依旧二分长度,分组。对于一组后缀,长度为len,我们判断是否满足每一个字符串都有出现两次,且两次出现的sa[i]>=len..所以记录每个串的最小值和最大值即可...
5.出现或反转后出现在每个字符串中的最长子串(poj1226)
和1的做法差不多..染色的时候把反转后的字符串染成一样的就行..
二、暴力枚举:
1.可重叠最长重复子串
子串出现2次或以上,也就是找到最大的height值即可..
2.不相同的子串的个数(spoj694,spoj705)
每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数...然后对于suffix(sa[i]),将产生n-sa[i]+1个前缀,用height数组去重即可..
3.最长回文子串(ural 1297)
分长度为奇数和偶数...将原串翻转后扔在后面,中间插一个辨别字符,一般用比所有字符小的字符..
枚举每个字母作为回文串中心:
(1)奇数:最长回文串为lcp(i,len-i+1)*2-1
(2)偶数:最长回文串为lcp(i,len-i+2)*2 (i=1时不成立)
4.连续重复子串(poj2406)
枚举k,判断lcp(1,k+1)是否等于n-k...预处理一下达到O(1)查询即可..
5.最长公共子串(poj2774,ural 1517)
枚举height[i],判断sa[i],sa[i-1]是否不属于同一个字符串,不属于则height[i]可计入答案..
三、有技巧的枚举、单调栈
1.重复次数最多的连续重复子串(spoj687 poj3693)
详见:http://www.cnblogs.com/EC-Ecstasy/p/4172751.html
2.长度不小于 k 的公共子串的个数 (poj3415)
单调栈O(n)维护...详见:http://www.cnblogs.com/EC-Ecstasy/p/4174671.html