后缀数组基础题poj1743详解_算法日常[16/100]
POJ1743
题目链接
题意
给定一个字符串,求最长重复子串,这两个子串不能重叠
解题思路
- 由于配置不是简单的匹配,有升降调的处理,但是我们无法确定升降的幅度,所以我们首先对输入的数组进行差值处理
- 可以发现同一个旋律的区段,它们的差值数组是相等的
- 因为之前我们处理成了差值,所以我们内卷了一个值,我们的差值相当于左右两个值,所以4个值代表着5个值
- 所以只要找到最长相同串长的长度不小于4的差值区段即可
- 由于需要求出最长的长度,考虑二分后验证可行性,二分区段的长度x,对差值数组求一遍后缀数组,将最长公共前缀大于等于x的划分成一组,如果存在一组的sa差值大于等于x+1(详见下面的重点解释),那么就表示x长度的差值数组能够被找到。二分结束即可得到答案。
没学后缀数组?
思路重点
为什么c+1,ans+1
二分检查的时候,最长公共前缀是x,sa差值却要大于x+1:
因为之前我们处理成了差值,所以我们内卷了一个值,我们的差值相当于左右两个值,所以4个值代表着5个值.所以最长公共字串只要在4的时候就相当于5,然后sa的差值还是要相间隔5才行==>这样真实的5个值也才是真的间隔5个值,所以同理答案也就是c+1
(ans+1
)
比如:
1 | 1 2 3 4 5 6 7 8 9 10 |
中间的'
也是1,但是代表的5,6,所以如果从这里开始和前面的4个1构成相同串的话,然后就重叠了一个,所以必须从'
后面1开始
我看了别的几个博主对于这题的分析没有谈及,这里,还有些代码没有考虑这里也能AC,说明数据都去卡时间了,没有卡下面这个特例:
1 | 9 |
为什么da函数的n值要加1而getheight函数不用
da要加一个位置的字符,让它比所有的字符都小,所以这个字符起始的后缀是其本身,其排名为0(rank[n]=0,sa[0]=n)
然而calheight却不要…因为calheight直接从rank值为1(rank为0的地方是添加的最小字符)的地方记到n,根本不会用到sa[0]
(排名为0的后缀),重点还有for中用的是<=..所以只要使用n.
for(i=1;i<=n;i++) ::rank[sa[i]]=i;
height分组为什么直接遍历下去分就好,不用吧height值相同的放在一起
AC代码1(推荐)
1 |
|
AC代码2(RMQ版)
此AC代码为2019年8月22日做HDU5008(因为那题最好还是用RMQ的后缀数组题)的时候发现的
不过这题用RMQ比较鸡肋,为什么? 请看下面的代码头部注释
1 | /* |
每天一句叨叨
我不管你是什么垃圾,我只看结果
要达到结果,你应该知道怎么做
I know you have the urge to give up!
But you must keep faith!
You do make a difference!