题目链接:
求字符串的重复次数最多的且字典序最小的字串。
很不错的题目。罗穗骞大牛论文的模板题,摘了大牛的详细题解,如下:
首先求第一问最大重复数。从N的范围来看O(N^2)虽不靠谱,但是起码能带来些有用的启示。方法有二,一是枚举开头位置求重复长度;二是枚举重复长度求开头位置。
第一种方法求最大重复数的方法MS也只有枚举重复长度然后去判……所以说我们从第二个方法入手。O(N^2)的方法是再枚举开头位置。我们来考虑一下能不能少枚举一些开头位置——更确切地说,能不能只枚举一些特殊位置,设当前枚举的长度为L,能不能只枚举0,L,2L,……这样的位置。见下图:
首先明确,枚举长度Len的时候,从一个位置求出的Lcp值表明从此处开始重复数为floor(Lcp / Len) + 1。
然后容易发现的问题就是,可能从某个枚举位置向前移动“一点”能够多一个周期,从而使重复数增加。从图上来看,这种状况发生的条件就是Lcp比满足这个重复数“必需的Lcp”要多,也就是Lcp % Len ≠ 0。不难发现,这时候我们向前移动Len - Lcp % Len的话,如果有下一个周期就会进去,否则也不会引起新的变化。所以说这种方法可行。
这样的话复杂度为n(1 + 1/2 + 1/3 + ... + 1/n) = O(nlogn)。有一个显而易见的优化,那就是只需要枚举到floor(n / 2)即可。但是后面的部分也少不了多少……
第二问是求最小字典序的答案。我采用了这样一种方法,那就是在第一步中记录能够达到最大重复数的重复长度的集合,然后按照sa[1],sa[2],sa[3],……的顺序去暴力枚举,每到一个位置就从小到大地判重复长度的集合中有没有可行的,如果有一个可行的就立即输出结果并退出。这样的做法能够保证正确性,虽然最坏情况下仍然有可能退化到O(n^2),但是要构造这样一组数据是比较困难的(得一直枚举到最后一个后缀,还得从1到Len / 2都能满足最大重复数)。对于非特殊构造的数据这一步的复杂度几乎是O(n),于是这个题就可以水过了。
我的代码:
1 //STATUS:C++_AC_422MS_11232KB 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include