2018牛客暑假多校三 E(KMP运用)

题目描述:

    给你一个字符串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
",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;
}
原文地址:https://www.cnblogs.com/Chen-Jr/p/11007256.html