题意:
给定一个由A~H8种字符组成,长度不超过1000000的字符串。问在这个字符串的最短不存在连续子串。若存在多个最短连续子串,输出字典序最小的一个。
题解:
先估计最长的答案是多少?我的估计是6个字符长,为什么?长度为6的字符串共有8^6≈250000,如果不存在公用的情况,需要长度250000*6的长度,已经长过1000000了。(有可能是7个字符长的,但7个字符的样例必须考虑字符共用,很难弄出来,所以6个字符就够了,如果想要保证正确性,可以用7个字符的)。
然后找出所有长度小于等于6的所有子串,由于子串是连续的,所以只用6*n的时间去查找。用f[i][j]标记存在的子串,i表示长度,j表示字符的哈希值(字符种类只有8个,用i位8进制就可以表示所有的情况)。最后遍历f数组,找出第一个未被标记的子串即可。
代码:
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#include <vector>
#include <cmath>
#include <cstdlib>
using namespace std;
const int maxn=1e6+10;
char a[maxn];
bool f[6][maxn];
int g[10],p[10];
void init()
{
int i,j,k;
p[0]=1;
for(i=1;i<=6;i++)
p[i]=p[i-1]*8;
}
void print(int a,int b)
{
int i,j,k,ans[10];
for(i=0;i<a;i++)
{
ans[i]=b%8;
b=b/8;
}
for(i=a-1;i>=0;i--)
printf("%c",ans[i]+'A');
printf("\n");
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int i,j,k,n;
memset(f,false,sizeof(f));
memset(g,0,sizeof(g));
scanf("%s",a);
n=strlen(a);
//printf("%d\n",n);
for(i=0;i<n;i++)
{
//printf("%d\n",i);
for(j=1;j<=6;j++)
{
g[j]=g[j]*8+(a[i]-'A');
if(i>=j)
{
g[j]-=(a[i-j]-'A')*p[j];
f[j-1][g[j]]=true;
//printf("%d %d\n",j,g[j]);
}
else if(i==j-1)
{
f[j-1][g[j]]=true;
}
//printf("%d %d\n",j,g[j]);
}
}
for(i=0;i<6;i++)
{
for(j=0;j<p[i+1];j++)
if(!f[i][j])break;
if(j<p[i+1])break;
}
print(i+1,j);
}
return 0;
}