题目大意:给你一个长度为n的字符串,问你它的每个前缀的最小循环周期,并输出其中周期 >1 的位置i,和它的周期k。
思路:先做kmp,这里有一个地方需要证明:如果一个串为周期串,设位置为 i ,那么(i - fail[ i ])肯定是它的最小循环节(周期为 1 也可以),循环周期为 k = (i+1)/(i - fail[ i ]),其中 (i + 1)%(i - fail[ i ]) == 0,长度要判断是不是符合,因为最前面那个有可能少,下标 i 从 0 开始。之后这道题目就很简单了。
上面那个东西感觉不是很好想。。。 = =
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1111111;
char str[MAXN];
int fail[MAXN];
void get_fail(char *s)
{
int len = strlen(s);
fail[0] = -1;
int j = -1;
for(int i = 1;i<len;i++)
{
while(j >= 0 && s[j+1] != s[i]) j = fail[j];
if(s[j+1] == s[i]) j++;
fail[i] = j;
}
}
int main()
{
int cas = 0;
int n;
while(~scanf("%d",&n) &&n)
{
scanf("%s",str);
get_fail(str);
printf("Test case #%d\n",++cas);
for(int i = 1;i<n;i++)
{
//printf("fail[%d] = %d\n",i,fail[i]);
int tmp = (i+1) % (i - fail[i]);
if(fail[i] > -1 && tmp == 0)
printf("%d %d\n",i+1,(i+1)/(i - fail[i]));
}
puts("");
}
return 0;
}