题意:给一个字符串S长度不超过10^6,求最大的n使得S由n个相同的字符串a连接而成,如:"ababab"则由n=3个"ab"连接而成,"aaaa"由n=4个"a"连接而成,"abcd"则由n=1个"abcd"连接而成。
定理:假设S的长度为len,则S存在循环子串,当且仅当,len可以被len - next[len]整除,最短循环子串为S[len - next[len]]
例子证明:
设S=q1q2q3q4q5q6q7q8,并设next[8] = 6,此时str = S[len - next[len]] = q1q2,由字符串特征向量next的定义可知,q1q2q3q4q5q6 = q3q4q5q6q7q8,即有q1q2=q3q4,q3q4=q5q6,q5q6=q7q8,即q1q2为循环子串,且易知为最短循环子串。由以上过程可知,若len可以被len - next[len]整除,则S存在循环子串,否则不存在。
解法:利用KMP算法,求字符串的特征向量next,若len可以被len - next[len]整除,则最大循环次数n为len/(len - next[len]),否则为1。
我的ac代码:
#include <cstring> #include <iostream> #include <cstring> #include <string> #include <cstdio> using namespace std; string str; int len,nx[1000000+10]; void getnext() { int j = 0,k = -1; nx[0] = -1; while(j<len) { if(k==-1||str[j]==str[k]) { nx[++j]=++k; }else { k=nx[k]; } } } int main(){ while(cin>>str) { if(str[0]=='.')break; len = str.length(); getnext(); if(len % (len-nx[len]) == 0) { cout<<len/(len-nx[len])<<endl; } else cout<<1<<endl; } return 0; }