题目大意


给出一个字符串,问其是由多少个相同的子串组成的。

思路


一道KMP题,考验对next[]数组的理解。

next[i]含义是模式串P的前i个字符组成的字符串Pi与其子串(即Pi的子串)匹配的最大长度。例如模式串P=”ababab”,P4就是模式串P的前4个字符组成的字符串”abab”,P4与其子串匹配的最大长度是2(即”abab”与”ab”匹配),则next[4]=2。

由next[i]的理论可以推知,len(p)-next[len(p)]是模式串P的“循环节”长度。为什么循环节长度上要加引号?因为模式串不一定恰好是“循环节”的整数倍,而是其整数倍的子串。在POJ的board里看到了一个非常好的样例,当模式串为”aabaabaa”时,循环节为3。所以在输出答案的时候,要判断模式串P的长度能否整除“循环节”,若不能整除,则输出1。

代码


#include<iostream>
#include<stdio.h>
using namespace std;
#define P_SIZE 1000000
int next[P_SIZE+2];
char P[P_SIZE+2];
//P是模式串。
void COMPUTE_PREFIX_FUNCTION(char P[])
//对next[]进行赋值。 
{
	int m=strlen(P+1);
	next[1]=0;
	for(int k=0,q=2;q<=m;q++)
	{
		while(k>0&&P[k+1]!=P[q])
			k=next[k];
		if(P[k+1]==P[q])
			k++;
		next[q]=k;
	}
}
int main()
{
	while(scanf("%s",P+1)&&strcmp(".",P+1))
	{
		COMPUTE_PREFIX_FUNCTION(P);
		int len=strlen(P+1),cycle=len-next[len];
		//len是模式串P的长度。 
		//cycle是“循环节”。 
		printf("%d\n",len%cycle?1:len/cycle);
		//若len不能整除cycle时,输出1。 
	}
}