题意:给出一个串,问最少在串末尾添加几个字符,才能让串中出现循环。
思路:这题要很好的理解next数组的性质才行,构造完next数组以后,有这样一个性质:字符串的最小循环节的长度为len-next[len],如果len%(len-next[len])==0,那么字符串的最小周期为len/(len-next[len]) 。
这是如何得到的呢,先来看下下面的图:
首先是①图,假设上面的是给定的串,求完next数组后,next[len]=6,如果发生转移,那么就会变成下面那个样子,这时候观察一下可以发现,原来绿色的abc这个串对应到蓝色的abc这个串上,也就是说这两个串相等,同时,蓝色的串又对应到红色的串上,这是可以一直往下递推的,因此,我们可以得出一个结论,那就是abc这个串是一个循环节。也就是说循环的串是S[next[len]+1……len]。
然后是②图,同样,上面是给定的串,下面是转移之后的状态,还是以上面的思路来看的话,bbbabc是一个循环节,然而,bbb却没用可以对应的字符,也就是说上面的串由于长度不够,因此无法构成循环,这样就比较明白了,如果len%(len-next[len])==0,那么循环节是恰好能形成循环的,否则不行。
这一道题也是一样的道理,要求的就是循环缺少的字符的个数,也就是相当于②图在bbb的位置的串的个数。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
char str[maxn];
int next[maxn];
void getnext(int n)
{
next[0]=next[1]=0;
for(int i=1;i<n;++i)
{
int j=next[i];
while(j&&str[i]!=str[j]) j=next[j];
next[i+1]=(str[i]==str[j])?j+1:0;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
scanf("%s",str);
int n=strlen(str);
getnext(n);
int ans=n-next[n];
if(ans==n) ans=n;
else if(n%ans==0) ans=0;
else ans=ans-n%ans;
printf("%d\n",ans);
}
return 0;
}