本篇博客来自于:https://blog.csdn.net/niushuai666/article/details/6965517
首先改了一下题目名称,貌似necklace拼写错误。。。
好了说正经的。题意:T组数据,每组数据给出一个字符串,询问至少要再加多少个字符使其变成一个有循环循环至少一次的字符串。
传送:http://acm.hdu.edu.cn/showproblem.php?pid=3746
还是一个kmp,模式串自己匹配自己。对于next数组的理解很重要:Next[i],s[0,...,i]的后缀与s[0...m-1]的前缀的最大匹配长度。
看了上面大佬的博客,感觉太强啦,自己找了几个串找了找规律。
可以发现一个规律,从第二个循环节的最后一个字符开始,所有的Next值都是连续的,并且到最后一个最后一个字符的Next的值,与从第二个循环节从1开始计数的结果是一样的,那么我们就可以得到这样一个计算字符串中的方式,使用Next数组!
假设图中S段是该串的最小循环节,S‘是末尾没有循环完的一小段,Next[m]是将最后一个字符进行匹配的位置,那么若S’不是第一个循环节,那么我们可以知道Next[m]会指向它前面那段S的相同位置。
从这个图我们可以得出循环节为 strlen(s)-Next[strlen(s)],需要添加的为 循环节-Next[strlen(s)]%循环节。
需要注意的是,当前循环整好结束,也就是不需要添加就已经是一个循环了的,满足之前讨论的最后一个字符的next值是有规律的,也就是Next[m]%循环节=0(循环次数大于等于2,如果是第一次循环的,那么我们可以通过判断循环节==strlen(s)来确定)
#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
char t[M];
int Next[M];
int m;
void kmp_pre()
{
memset(Next,0,sizeof(Next));
int i,j;
Next[0]=j=-1;
i=0;
while(i<m)
{
while(j!=-1 && t[i]!=t[j])
j=Next[j];
Next[++i]=++j;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",t);
m=strlen(t);
kmp_pre();
int lh=m - Next[m];
if(lh!=m && m%lh==0)
{
puts("0");
continue;
}
printf("%d\n",lh-(Next[m])%lh);
}
return 0;
}