题意是求前n个数的循环节的个数:
例如:aabaabaabaab中 ,
前2个字符aa,循环节为a, 所以为2 2;
前6 个 字符循环节为aab, 所以为6 2;
前9个 字符循环节为aab, 所以为9 3;
前12 个 字符循环节为aab,所以为12 4;
关键是如何求循环节,首先还要熟悉next数组的意思,next[j]=k,表示j前面k个元素与开头的前k个元素相同,但是中间可能有循环的元素,如何去除重复的元素
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
a[i] | a | a | b | a | a | b | a | a | b | a | a | b | |
next[i] | -1 | 0 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
2*next[i]-i即可以求出中间重复的元素;
(原因:初中因该学过,给N个元素,前k个元素和后k个元素相等,求重复的元素个数)
next[i]-(2*next[i]-i) == i-next[i]即是最小的循环节;
i/最小循环节 = 循环的次数 ;
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX = 1000000 + 5;
int next[MAX],len;
char a[MAX];
void get_next()
{
int i=0,j=-1;
next[0]=-1;
while(i<len)
{
while(j>-1&&a[j]!=a[i])
j=next[j];
j++;
i++;
next[i]=j;
}
}
int main()
{
int ncase=0;
while(scanf("%d",&len)&&len)
{
scanf("%s",a);
int circle;
get_next();
printf("Test case #%d\n",++ncase);
for(int i=1;i<=len;i++)
{
circle=next[i]-(2*next[i]-i);
if(2*next[i]-i>=0 && i%circle == 0)
{
printf("%d %d\n",i,i/circle);
}
}
printf("\n");
}
return 0;
}