poj 1961 Period [kmp, next数组的用法]

题目链接  http://poj.org/problem?id=1961

大致题意:

给出一个串,输出第i位之前的串是由多少个相同的子串组成的。输出i的子串的个数。

思路:

在next数组中加一句判断即可

if(i%(i-j) == 0 && i/(i-j) > 1) {

  printf("%d %d\n", i, i/(i-j));

}

这条语句是什么意思?

要了解next数组的求法,那么就不难理解了。

对于 i%(i-j) == 0

遍历到第i个字符,前面字符串的长度为i,且前面字符串的前缀和后缀相等的字符的个数是j个。如果想要得到像题意那样的序列,则j必满足j》=i/2,假设j<i/2,那么中间肯定有一些字符是和前后缀没有关系的,所以不能够得到题中所说的序列。所以要想满足题中的序列必须有i%(i-j) == 0.

对于 i/(i-j) > 1。

这个就是最多有多少个相同的子串。因为前面串的长度为i,而又满足i%(i-j) == 0,题意中要求子串最少为2,所以i/(i-j)就是答案,要大于1。

代码:

#include<stdio.h>
#include<string.h>

char str[1000002];
int next[1000002];

int main()
{
	int n, t = 1;
	while(scanf("%d", &n), n) {
		printf("Test case #%d\n", t++);
		scanf("%s", str);
		int len = strlen( str );
		int i, j;
		i = 0;
		j = -1;
		next[0] = -1;
		while( i < len ) {
			if(j == -1 || str[i] == str[j]) {
				i++;
				j++;
				if(i%(i-j) == 0 && i/(i-j) > 1) {
					printf("%d %d\n", i, i/(i-j));
				}
				next[i] = j;
			} else {
				j = next[j];
			}
		}
		printf("\n");
	}
	return 0;
}

  

posted @ 2012-11-01 20:19  小猴子、  阅读(345)  评论(0编辑  收藏  举报