POJ Period KMP next數組的理解

一個字符串的前綴是從第一個字符開始的連續若干個字符,例如"abaab"共有5個前綴,分別是a, ab, aba, abaa,  abaab。

 

我們希望知道一個N位字符串S的前綴是否具有循環節。換言之,對於每一個從頭開始的長度爲 i (i 大於1)的前綴,是否由重複出現的子串A組成,即 AAA...A (A重複出現K次,K 大於 1)。如果存在,請找出最短的循環節對應的K值(也就是這個前綴串的所有可能重複節中,最大的K值)。

輸入

輸入包括多組測試數據。每組測試數據包括兩行。
第一行包括字符串S的長度N(2 <= N <= 1 000 000)。
第二行包括字符串S。
輸入數據以只包括一個0的行作爲結尾。

輸出

對於每組測試數據,第一行輸出 "Test case #“ 和測試數據的編號。
接下來的每一行,輸出前綴長度i和重複測數K,中間用一個空格隔開。前綴長度需要升序排列。
在每組測試數據的最後輸出一個空行。

樣例輸入

3
aaa
12
aabaabaabaab
0

樣例輸出

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4

KMP板子題,理解next數組就好

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstdlib>
#include<deque>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>P;
const int len=1e6+5;
const double pi=acos(-1.0);
const ll mod=99991;
char str[len]; 
int nex[len];
int n;
void get()
{
	nex[1]=0;
	for(int i=2,j=0;i<=n;++i)
	{
		while(j>0&&str[i]!=str[j+1])j=nex[j];
		if(str[i]==str[j+1])j++;
		nex[i]=j;
	}
}
int main()
{	
	int Case=0;
	while(scanf("%d",&n))
	{
		if(n==0)break;
		scanf("%s",str+1);
		get();
		printf("Test case #%d\n",++Case);
		//nex[i]的意義爲文本串以i結尾(非前綴子串,也叫真前綴)時,與前綴最大的匹配長度 
		//比如 aabaabaab  nex[6]=3,nex[9]=6 
		for(int i=2;i<=n;++i)
		{
			if(i%(i-nex[i])==0&&i/(i-nex[i])>1)//其中i%(i-nex[i]) ==0保證爲循環字符串,
			//   i/(i-nex[i]) >1保證循環節長度大於1 
				printf("%d %d\n",i,i/(i-nex[i]));
		}
		puts("");
	}
} 




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章