题目
找出一个给定串的所有循环节,
输出这个个数,和所有的前缀长度
思路来源
https://blog.csdn.net/weixin_41380961/article/details/80278317
https://www.cnblogs.com/ikids/articles/4658884.html
题解
考察的是对next[]数组的理解
令m=strlen(t),则m-next[m]显然是一个答案
为什么呢,因为t(1,next[m])=t(m-next[m],m),
next[m]把串分成三部分,第一部分和第三部分相同,
这样第一部分和第二部分就构成了一个循环节,
我们递归该过程,
比如下面那个串,第一次next[m]=4,
递归下去对于abab,next[4]=2,
那就说明t(1,2)=t(3,4),而t(1,4)=t(8,11),
这就说明t(1,2)=t(10,11),从而把串分成三部分,第一部分和第三部分相同
那么前两部分又是一个答案
每次next[]的值是可能与最后的串的部分相同的,
那么加上中间的这部分(即用整串减去后面那部分next[]的值),
就是一个新的循环节
心得:
最小循环节不能代表所有循环节
ababaaaabab用最小循环节来求答案是7、11,正确答案是7、9、11
在补六七个月前wa的题
感觉当时的码风真是稚嫩
感觉自己当年简直沙雕沙枯了
错了也不知道看答案就一直在莽QAQ
现在想想,真的是……哎
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
char t[1000005];
int net[1000005];
int m;
queue<int>q;
void kmppre()
{
int i=0,j=net[0]=-1;
m=strlen(t);
while(i<m)
{
while(j!=-1&&t[i]!=t[j])j=net[j];
net[++i]=++j;
}
int k=m;
while(k>0)
{
k=net[k];
q.push(k);
}
}
int main()
{
int T,num;
scanf("%d",&T);
for(int i=1;i<=T;++i)
{
scanf("%s",t);
kmppre();
num=0;
printf("Case #%d: %d\n",i,q.size());
while(!q.empty())
{
if(!num)printf("%d",m-q.front());
else printf(" %d",m-q.front());
num++;
q.pop();
}
puts("");
}
return 0;
}