题目描述
有 n 个长度为 9 且只包含数字字符且 互不相同 的串。
需要对于每个串找到一个 长度最短 的识别码,使得这个识别码 当且仅当 为这个串的子串。
(1leq nleq7*10^4)
题解
虽然可以用map糊过,但我们选择字典树
考虑暴力,我们可以把所有子串插入字典树,然后暴力枚举
但这样空间不够
再想想优化,其实我们可以不用把每个子串都插入
只需要插入每个串的所有后缀
接着再枚举所有子串匹配即可
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int inf=0x7fffffff;
typedef long long ll;
#define maxn 5000005
char a[70009][10];
int n,root=1;
int p[70009];
int tr[maxn][10];
int vis[maxn];
bool buok[maxn];
int cnt=2;
bool tag=0;
int timemark=1;
void Add(int pos,int s,int t)
{
int now=root;
for(int i=s;i<=t;i++)
{
int x=a[pos][i]-'0';
if(!tr[now][x])tr[now][x]=++cnt;
if(!vis[now])vis[now]=timemark;
else if(vis[now]!=timemark)buok[now]=1;
now=tr[now][x];
}
if(!vis[now])vis[now]=timemark;
else if(vis[now]!=timemark)buok[now]=1;
}
int l=0;
bool Query(int pos,int s,int t)
{
l=0;
int now=root;
for(int i=s;i<=t;i++)
{
int x=a[pos][i]-'0';
p[++l]=x;
now=tr[now][x];
//cout<<x;
}
//cout<<endl;
if(buok[now]==1)return 0;
return 1;
}
signed main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",a[i]);
}
tag=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<9;j++)
{
Add(i,j,8);
}
timemark++;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<9;j++)
{
bool flag=0;
for(int k=0;k+j<9;k++)
{
if(Query(i,k,k+j))
{
// cout<<"I:"<<i<<endl;
for(int q=1;q<=l;q++)printf("%d",p[q]);
printf("
");
flag=1;
break;
}
}
if(flag)break;
}
}
return 0;
}