string stringstring
Time Limit: 2000/1000 MS(Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2240 Accepted Submission(s): 703
Problem Description
Uncle Mao is awonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy thathe left the problem to you. I hope you can give him a solution.
Given a string s, we define a substring that happens exactly k times as animportant string, and you need to find out how many substrings which areimportant strings.
Input
The first linecontains an integer T (T≤100) implying thenumber of test cases.
For each test case, there are two lines:
the first line contains an integer k (k≥1) which is describedabove;
the second line contain a string s (length(s)≤105).
It's guaranteed that ∑length(s)≤2∗106.
Output
For each testcase, print the number of the important substrings in a line.
Sample Input
2
2
abcabc
3
abcabcabcabc
Sample Output
6
9
Source
2017 ACM/ICPC Asia Regional Shenyang Online
据说这题是另一道SPOJ的一道后缀自动机的弱化版,好腻害的样子……这里用后缀数组解。
大致题意,给你一个字符串,然后问你在这个字符串中,恰好出现k次的不同子串有多少个(可以相互重叠)。
首先明确所有后缀数组题目都很重要的一点,即所有子串都是某个后缀的前缀,大部分都可以转化为lcp的问题。然后我之前在POJ上做了一道题,没有写博客,是求一个字符串中最长的出现至少k次的子串的长度(POJ 3261)。这两道题目类似,在求至少k次的时候用的是同样的方法。
对于这个出现至少k次的问题,我们可以这么考虑。如果一个子串出现了多次,设出现的起始位置为i和j,那么他们的后缀排名sa[]一定是相邻的,即abs(sa[i]-s[j])=1。如此一来,如果出现k次,那么这k个子串对应的后缀排名也是连续k个,且重复出现的部分最大长度即为这连续一段的height[]的rmq。所以说,至少出现k次,相当于在长度为k的height数组的区间内求rmq,也即区间的很多后缀的lcp是这个区间的最小值。
对于POJ那题,我们二分一个最大长度,然后扫描height数组,看最大连续height值大于k的长度是否大于这个二分的长度即可。而对于此题,设长度为k的区间的最长公共前缀为lcp,那么就会产生lcp个新的满足条件的子串,统计即可。但是,注意了,这个并不是我们要求的。我们需要的是出现恰好k次(exactly),而不是至少k次。然而这个问题也是经典问题,很容易解决。我们用容斥原理,用至少k次的答案减去至少k+1次的答案即可。而这个k+1多出来的1可以是往前多出现一次或者往后多出现一次,所以说两次都要减去。不过在减的过程中,我们发现多减了一个出现k+2的答案,这个画一个区间图更好理解。按照这样子容斥累加最后答案即可。
最后要注意,当k==1的时候,会发现rmq区间是一个单位区间,这个时候的lcp不能是对应height数组的值,显然应该就是这个后缀本身的长度,这里做一个特判。然后还需要用LL。具体见代码: