这道题应该可以早就过的,却拖了一下午=_=,主要是我遇到了很奇怪的问题,现在还不知道原因。
那就是我一开始写的输入是:
while(T--&&(scanf("%s",s+1)!=EOF)) { ...... }
一直wa,最后实在感觉没错,很无奈,照着别人的代码一个字符一个字符比对,发现改成以下格式就过了:
while(T--) { scanf("%s",s+1); ...... }
我之前也这么写过,应该没问题,猜测了很多原因,包括出题者给的数据不是严格的T组数据等等,但都被我排除了,所以暂时我还是不知道原因是什么,在群里问了也没人回,所以先暂且把它叫做灵异问题吧。
下面正式进入正题。这道题考察的是kmp next数组的理解,根据next数组求出字符串最小循环节,我用的是比较一般的递推方法。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int MAXN=100005 ; int jump[MAXN]; void PrintJump(char *str) { jump[0] = -1; jump[1] = 0; int len = strlen(str+1); int j=1,k; while(j<len) //计算jump[j+1] { k = jump[j]; //已知jump[j]==k while(k!=-1&&str[k+1]!=str[j+1]) k = jump[k]; jump[j+1] = k+1; j++; } } char s[MAXN]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%s",s+1); PrintJump(s); int len = strlen(s+1); int c=1; for(int i=2;i<=len;i++) { int t=jump[i]; int tc=i%c; if(tc==0) tc+=c; while(t>tc) t=jump[t]; if(t<tc) { c=i-jump[i]; } //printf("%d %d\n",c,t); } //printf("count = %d\n",c); int ans=len%c; if(c==len) ans = len; else if(ans) ans = c-ans; printf("%d\n",ans); } }
但有人已经证明出来len-next[i]就是字符串的最小循环节,这样复杂度就大大降低了:http://www.cnblogs.com/wuyiqi/archive/2012/01/06/2314078.html。值得学习。