给一个字符串S(长度小于50W),要求构造出一个最短的并且不是S的子串的字符串,字符集为{a,b}。
如果构造不出长度为k的目标串的话,说明S中一定包涵长度为k的所有子串的情况,那么S的长度至少就是K*2^K,想通了这个就会发现这题的答案一定小于15,那么直接枚举就行了..枚举每个长度L,遍历S的时候用一个bit[i]表示以i为结尾的长度为L的字符串的值(因为只有a,b,直接hash成一个二进制数就行),如果对与某个长度如果字符串的种类没达到2^L的话,L就是答案了,找到一个没在S中出现的串就行。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <string>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
int n,m,len;
char s1[550000],s2[550000];
int bit[550000];
int last[550000];
bool ok[1100000];
char out[100];
bool work(int l)
{
map<int,int>hash;
map<int,int>::iterator it;
memset(ok,true,sizeof ok);
for (int i=l-1; i<len; i++)
if (i-1>=0) bit[i]=last[i-1]*2+(s1[i]-'a');
memcpy(last,bit,sizeof bit);
int cnt=0;
for (int i=l-1; i<len; i++)
if (hash.find(bit[i])==hash.end())
{
cnt++;
hash[bit[i]]=bit[i];
}
if (cnt==(1<<l)) return false;
else
{
printf("%d\n",l);
for (it=hash.begin(); it!=hash.end(); it++)
ok[it->first]=false;
for (int i=0; i<(1<<l); i++)
if (ok[i])
{
int num=0;
while (i)
{
out[num++]=(i & 1);
i>>=1;
}
for (int j=l-1; j>=0; j--)
printf("%c",'a'+out[j]);
return true;
}
}
return false;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%",&n);
gets(s1);
memset(bit,0,sizeof bit);
memset(last,0,sizeof last);
len=strlen(s1);
for (int i=1; i<=20; i++)
{
if (work(i)) break;
}
return 0;
}