原题链接:http://codeforces.com/contest/861/problem/D
大致题意:给出一些字符串,问每一个字符串在这个字符串集合里独有的最小长度的子串。
建立一颗字符串树,然后把每一个字符串的子串都暴力加入进去,同时在每个节点记录第几个字符串经过这个节点。独有的子串就是从根节点到某个只有一个字符串经过的节点,路径构成的子串就是这个字符串的独有的子串。对于最小长度的限制,我是用11进制来更新最小值就可以得到最小长度的独有子串就可以了。
代码:
#include <bits/stdc++.h>
using namespace std;
inline void read(int &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
inline void read(long long &x){
char ch;
bool flag=false;
for (ch=getchar();!isdigit(ch);ch=getchar())if (ch=='-') flag=true;
for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
x=flag?-x:x;
}
const int maxn = 71000;
int son[maxn*20][11];
set<int> tree[ maxn*20 ];
int n;
int root, tot;
char s[maxn][15];
int a[maxn][15];
void add(int num, int st ,int ed){
int now=root;
for (int i=st;i<=ed;i++)
{
if (son[now][ a[num][ i ] ]==0)
son[now][ a[num][ i ] ]=++tot;
tree[now].insert ( num );
now=son[now][ a[num][ i ] ];
}
tree[now].insert ( num );
}
long long ans[maxn];
void dfs(int x,long long now){
if( (x!=1) && ( tree[x].size()==1 ) )
{
int y=*tree[x].begin();
ans[ y ]=min( ans[ y ] , now );
if ( ans[ y ] ==0 )
ans[ y ]=now;
return ;
}
for (int i=1;i<=10;i++)
if ( son[x][i] != 0 )
dfs(son[x][i],now*11ll+1ll*i);
}
int kkk[ 10000 ];
void out(long long x){
int cnt=0;
while ( x )
{
kkk[++cnt]=x%11;
x=x/11;
}
for (int i =cnt ; i>=1;i--)
printf("%d",kkk[i]-1);
puts("");
}
int main(){
read(n);
for (int i=1;i<=n;i++)
{
gets(s[i]);
for (int j=0;j<9;j++)
a[i][j]=s[i][j]-'0'+1;
}
/*
for (int i=1;i<=n;i++)
{
for (int j=0;j<9;j++)
printf("%d ",a[i][j]);
puts("");
}
*/
root=1,tot=1;
for (int i=1;i<=n;i++)
{
for (int j=0;j<9;j++)
for (int k=j;k<9;k++)
add( i ,j ,k );
}
for (int i=1;i<=n;i++)
ans[i]=0;
dfs(1,0ll);
for (int i=1;i<=n;i++)
{
out(ans[i]);
//printf("%I64d\n",ans[ i ] );
}
return 0;
}