字符串循环节 POJ2406 Power Strings 为例
题意:找到字符串一个循环节使其循环次数最大,输出最大循环次数,没有循环节输出1
题解:KMP的next数组,next[ i ]表示前 i 个字符相同前后缀的最大长度,所以next[ len ]表示整个字符串的相同前后缀的最大长度,如果 len % (len-next[len])==0,len-next[len]就是最小循环节的长度了,答案即为len / (len-nx[len]),否则最小循环节长度为len,答案为1;
简单证明一下:若 len%(len-nx[len])==0,则整个字符串相同前后缀的最大长度一定大于等于len/2,等于len/2的显然,略过不表,大于len/2,表示前后缀有公共部分,那就会出现两种情况:
第一种
如图所示,L表示最大后缀的起点,R表示最大前缀的终点,S表示len-next[len],显然满足 len % (len-next[len])==0,答案即为len / (len-nx[len])

第二种:
如图所示,较之上图,公共前后缀多了一个尾巴T,显然这个T一定是S的一段前缀,这显然不满足len % (len-next[len])==0,所以答案为 1

好了 扯完了,写这篇主要不是为了写这道题的题解,只是想记录一下这个方法和思想,顺便写一下题解=。=
题目很简单,但是还是贴一下代码吧
#include<cstring> #include<cstdio> using namespace std; const int maxn=1000010; char s[maxn]; int nx[maxn]; void getNext(char * p) { nx[0] = -1; int i = 0, j = -1; int len=strlen(p); while (i < len) { if (j == -1 || p[i] == p[j]) { ++i; ++j; nx[i] = j; } else j = nx[j]; } } int main() { while(scanf("%s",s)&&s[0]!='.') { getNext(s); int len=strlen(s); printf("%d\n",len%(len-nx[len])?1:len/(len-nx[len])); } return 0; }

浙公网安备 33010602011771号