给定若干个长度 ≤ 1000000 的字符串,询问每个字符串最多是由多少个相同的子字符串重复连接而成的。[循环节]
如:ababab 则最多有 3 个 ab 连接而成。
输入格式:
输入若干行,每行有一个字符串。特别的,字符串可能为 . 即一个半角句号,此时输入结束。
样例:
输入:
abcd
aaaa
ababab
.
输出:
1
4
3
数据范围与提示
字符串长度 <= 10^6 。
KMP
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
char s[1000005];
int next[1000005];
int len;
void getnext(){
int j=0,k=-1;
next[0]=-1;
while(j<len)// 0 到ken
{
if(k==-1 || s[j]==s[k] )//最开始 或成功匹配
{
k++;
j++;
next[j]=k;
}
else //匹配失败
{
k=next[k];//回退
}
}
}
int main(){
while( scanf("%s",s)!=EOF && s[0]!='.')
{
/*
思路:
一个字符存在循环节,
当且仅当它的长度 len能被 len - next[len]整除,
并且它的最短循环节就是
下标在区间 [1,len-next[len]]内的它的子串(下标从 1 开始)
*/
len=strlen(s);
getnext();
if( len % (len-next[len] ) ==0 )//算出KMP的末位 与 长度的差值就是循环字串的长度
{
printf ("%d\n",len / (len - next[len]) );//整个长度能整除循环字串的长度则为最终答案,否则为1
}
else{
printf ("1\n");
}
}
return 0;
}
另一个
#include <bits/stdc++.h>
using namespace std;
int nxt[1000100];
char s[1000100];
int main()
{
while(~scanf("%s",s+1)&&s[1]!='.')
{
int n=strlen(s+1);
nxt[1]=0;
for(int i=2,j=0;i<=n;i++)
{
while(j>0&&(j==n||s[i]!=s[j+1])) j=nxt[j];//匹配不成功
if(s[i]==s[j+1]) j++;
nxt[i]=j;
}
if(n%(n-nxt[n])==0&&nxt[n])
printf("%d\n",n/(n-nxt[n]));
else
puts("1");
}
return 0;
}