Description
给你一个字符串,它是由某个字符串不断自我连接形成的。 但是这个字符串是不确定的,现在只想知道它的最短长度是多少.
Input
第一行给出字符串的长度,1 < L ≤ 1,000,000. 第二行给出一个字符串,全由小写字母组成.
Output
输出最短的长度
Sample Input
8
cabcabca
Sample Output
3
HINT
对于样例,我们可以利用"abc"不断自我连接得到"abcabcabc",读入的cabcabca,是它的子串
题意分析
Hint中已经有解释,一个子串“abc”不断自我连接成“abcabcabc”,那么“cabcabca”也是它的一个子串,其中的“abc”是最小“循环节”,或者说“cab”是最小“循环节”
解题思路
这也是一个kmp的题目,对于给定的长度为L的字符串“cabcabca”计算出对应的next[]数组,那么L-next[L]就是最小循环节的长度,为什么呢?下面分析一下:
由上图可见,L=8,next[8]=5,最小循环节的长度= L-next[8] = 8-5 = 3,也就是“cab”的长度是3
为什么?
因为next[L]中存放的是这个字符串最大共同前后缀的长度(不包括整个串本身),这个值其实就是从第二个循环节开始一直到最后一个字符的长度,用整个字符串的长度 减去 这个值,得到的就是第一个循环节的长度。
举一个例子,假设一个循环节的长度为5,这个循环节经过多次重复(最后一次重复可能是不完整的)后得到一个字符串,我们这样表示:
12345 12345 12345 123
在这里,循环节“12345” 一共重复了4次,最后一次只有“123”,总长度L=18。
那么这个字符串,最大的后缀就是从第2次循环开始一直到最后一个字符:12345 12345 123;当然最大的前缀也是:12345 12345 123。所以用总长度减掉最大后缀长度 ,得到的就是第一个循环节的长度,也就是最小循环节的长度了。
这个最大后缀长度,正好是最后一个next值,即next[L]。
思路有了,代码就好办了,对于一个串,先计算出他的next[]值,然后用L-next[L]即可。
首先定义变量,因为题中说1 < L ≤ 1,000,000,所以定义一个字符数组s[1000010]
另外给他定义一个next数组 int next[1000010]
计算next数组的代码和以往一样,通过一个for循环和i、j来实现,
完整代码如下:
#include<cstdio>
#include<cstring>
char s[1000010];
int next[1000010];
int main()
{
int i,j,len;
scanf("%d%s",&len,s+1);
for (i=2,j=0;i<=len;i++)
{
while (j&&s[i]!=s[j+1]) j=next[j];
if (s[i]==s[j+1]) j++;
next[i]=j;
}
printf("%d\n",len-next[len]);