PKU 1961(KMP判断循环段位置)

/*

  基本题意:给一个字符串,如果在前 i 位置处满足连续循环A^K(A:单位循环段,

              K:循环个数),则输出i和K

  这题跟pku 2406差不多

  YY :      kmp 保存 next[i],如果满足 i能被单位长度(i - next[i])整除,说明

             (i - next[i])是单位循环段A,i /(i - next[i])也就是K。

        举两个例子应该就能理解

    例一:

      i     :     12345678 

      字符串 :      abababab

      next[i]:      00123456                                                                                                   

       这个例子假如当i等于8时,next[i] = 6; K也就是4,如果你有“ 你只是看

       了后面[next[i]+1,i ] 这一段,不能代表全部是循环,可能中间有的地方跟

       你说的循环点不一样?”这种问题的话,看下面个例子

    例二:

      i      :     1234567 

      字符串 :     abcabab

      next[i]:     0001200            

       这个例子中位置6.7就是你想的情况,但next[i] = 0;所以是不可能出现循环点的,

       而位置4.5即便next[i] != 0,但i不能整除(i - next[i]),所以也不会是循环段。

*/

代码如下

#include <stdio.h>
#include <string.h>
char s[1000003];
int next[1000003];
int len;

void GetNext_Print()
{
	int i,j;
	s[0] = '#';
	len = strlen(s);
	next[1] = 0;
	j=0;
	for(i=2;i<len;i++)
	{
		while(j>0 && s[j+1]!=s[i])
			j = next[j];
		if(s[j+1] == s[i]){
			j++;
		}
		next[i] = j;
		//以下是判断是否是循环点
		int l = i - next[i];
		if(l == i) continue;
		if(i%l == 0) //
			printf("%d %d\n",i,i/l);
	}
}

int main()
{
	int n,cas = 1;
	while(scanf("%d",&n)!=EOF && n)
	{
		getchar();
		scanf("%s",s+1);
		printf("Test case #%d\n",cas++);
		GetNext_Print();
		printf("\n");
	}
	return 0;
}


posted @ 2011-02-19 20:18  kfinder  阅读(370)  评论(0编辑  收藏  举报