[问题描述]
对于两个字符串x、y, 如果将若干个x 串首尾相连后得到s 串,且y 是s 的子串,那
么我们称x 为y 的覆盖子串。
( 如,将三个abc 首尾相连得到abcabcabc,而bcabcab 是abcabcabc 的子串,所以abc
是bcabcab 的一个覆盖子串)
现在已知字符串y,求y 的最小覆盖子串。
若有多个覆盖子串长度相同,输出字典序最小的一个
[输入格式]
一个字符串y
[输出格式]
输出有两行
第一行输出y 的最小覆盖子串的长度
第二行输出y 的最小覆盖子串
[输入样例]
对于两个字符串x、y, 如果将若干个x 串首尾相连后得到s 串,且y 是s 的子串,那
么我们称x 为y 的覆盖子串。
( 如,将三个abc 首尾相连得到abcabcabc,而bcabcab 是abcabcabc 的子串,所以abc
是bcabcab 的一个覆盖子串)
现在已知字符串y,求y 的最小覆盖子串。
若有多个覆盖子串长度相同,输出字典序最小的一个
[输入格式]
一个字符串y
[输出格式]
输出有两行
第一行输出y 的最小覆盖子串的长度
第二行输出y 的最小覆盖子串
[输入样例]
bcabcab
[输出样例]
3
abc
[样例解释]
见问题描述
[数据范围]
设字符串y 的长度为N
对于30%的数据, N <= 5000
对于100%的数据, N <= 10^6
对于每一个串我们可以求出它的循环节的长度 len-next[len-1] (不懂的自行脑补);
剩下的就是排序了,由于长度可以很大所以我们按开头的位置枚举。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
char str[2100000];
int next[1100000],n,x;
int getnext()
{
next[0]=0;
for(int i=1;i<n;i++)
{
int temp=next[i-1];
while(temp&&str[temp]!=str[i])
temp=next[temp-1];
if(str[temp]==str[i])
next[i]=temp+1;
else
next[i]=0;
}
int xunhuan = n-next[n-1];
return xunhuan;
}
bool cmp(int aa,int bb)
{
for(int i=0;i<x;i++)
{
if(str[i+aa]!=str[i+bb])
{
return str[i+aa]<str[i+bb];
}
}
}
int main()
{
//freopen("b.in","r",stdin);
//freopen("b.out","w",stdout);
scanf("%s",str);
n=strlen(str);
int len=getnext();
printf("%d\n",len);
for(int i=n;i<=n*2;i++)
{
str[i]=str[i-(n/len)*len];
}
int i,j,l;
i=0;j=1;
while(i<len && j<len)
{
for(l=0;i+l<=2*len&&j+l<=2*len && str[i+l]==str[j+l];++l);
if(str[i+l]==str[j+l])
break;
if(str[i+l]<str[j+l])
j+=l+1;
else i+=l+1;
if(i==j)++j;
}
for(l=0;l<len;++l)
printf("%c",str[l+i]);
return 0;
}
/*
bcabcab
*/