2018牛客网暑期多校训练赛第三场 E题 Sort String

题目链接

题意:

给了一个字符串,Si是由下标i到字符串末尾加上0到i-1组成的字符串,只有当字符串Si和Sj是相同的才算是在一组,问字符串可以分成多少组并按字典序最小的输出每组中的i下标。

思路:

看到这题想到了哈希,然后哈希改来改去改到95%死活不过。还有9分钟的时候队友想出来了正解,可惜来不及敲了QAQ||

这题最后是如果字符串是有循环节,并且完全由循环节构成的才能进行分组。

如果没有完全由循环节构成的话,就像这样的图,将字符串复制一份到后面,会发现中间是断开的连不上。

所以知道了这点就好做了。用KMP来算循环节的大小就好了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e6+5;
char t[maxn];
int ne[maxn];
void makenext(const char p[],int ne[],int len)
{
    ne[0]=0;
    for(int i=1,k=0;i<len;i++)
    {
        while(k>0&&p[i]!=p[k]) k=ne[k-1];
        if(p[i]==p[k]) k++;
        ne[i]=k;
    }
}
int main()
{
    int len;
    scanf("%s",t);
    len=strlen(t);
    makenext(t,ne,len);
    int c=len-ne[len-1];//循环节
    if(len%c==0&&ne[len-1]!=0)
    {
        printf("%d\n",c);
        int r=len/c;//每组的个数
        for(int i=0;i<c;i++)
        {
            int pos=i;
            printf("%d ",r);
            for(int j=1;j<=r;j++)
            {
                if(j==r)
                    printf("%d\n",pos);
                else
                    printf("%d ",pos);
                pos+=c;
            }
        }
    }
    else
    {
        printf("%d\n",len);
        for(int i=1;i<=len;i++)
        {
            printf("1 ");
            printf("%d\n",i-1);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/timeclimber/article/details/81225302