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; }