题目描述:
给你一个字符串S,你要对字符串S的每一位i将前i位的字符串移动到尾部形成一个新的字符串,如果形成的字符串相同则归为一类Li。现在让你将Li类按照字典序排序,并让你输出每一类的数量和每一类中字符串对应的下标i。
题目分析:
观察可以发现,将字符串移动形成新的字符串,当且仅当字符串中存在循环节时,才会出现新构成的字符串相同。因此这个问题就转化成求一个字符串的循环节的问题。
至此,这个问题就可以用kmp中的next数组进行计算。(有一个重要结论,如果对于一个长度为L的字符串,如果L%(L-next[L])==0则代表它具有循环节,且循环节的长度为L-next[L])
代码:
#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
int nex[maxn];
char str[maxn];
void get_next(char *s){//获取next数组
int i,j;
j=nex[0]=-1;
i=0;
int len=strlen(s);
while(i<len){
while(j!=-1&&s[i]!=s[j]) j=nex[j];
nex[++i]=++j;
}
}
int main()
{
scanf("%s",str);
get_next(str);
int len=strlen(str);
int tmp=len-nex[len];
if(len%tmp!=0){//如果没有循环节,则每个都类都为1
cout<<len<<endl;
for(int i=0;i<len;i++){
printf("1 %d\n",i);
}
}
else{
cout<<tmp<<endl;//字符串的种类的数目为循环节的长度
for(int i=0;i<tmp;i++){
cout<<len/tmp;//每个字符串种类的个数
for(int j=i;j<len;j+=tmp){
cout<<" "<<j;
}
puts("");
}
}
return 0;
}