题解:AT_arc219_a [ARC219A] Similarity
前置芝士:trie 树
声明:以下称字符串
题意概述:
给定 Yes,第二行输出 No。
正难则反,考虑对于一个
:::info[
定义一个长度为
:::
因此,设
这不就是赤裸裸的 trie 树上跑 dfs,找到不存在的节点吗?
考虑把每个
- 若
p 没有0 儿子,则T 的第k 位为0 ,前k-1 位是 dfs 决定好的,后m-k 位随意(这里全部取0 更方便)。找到答案。 - 否则,若
p 没有1 儿子,则T 的第k 位为1 ,其余同上。找到答案。 - 否则,
T 的第k 位分别选择0 和1 继续 dfs,判断是否成立。
如果把 trie 树跑满了还是没有找到答案,那就是没有答案了。
为什么找到空节点一定是对的呢?因为假设当前的
现在分析复杂度。
最坏情况下,trie 树每层放满节点且不能超过
读入和构建 trie 树的时间复杂度都是
既然足以通过本题,那么代码如下:
const int N=20005,M=105;
int n,m;
char s[M],ans[M];
int tot,son[N*M][2]; //记得将空间开够
inline void add()
{
int pos=0;
for(int i=1,num=0;i<=m;i++)
{
num=(s[i]-'0');
if(!son[pos][num]) son[pos][num]=++tot;
pos=son[pos][num];
}
}
int dfs(int p,int k)
{
if(k==m+1) return -1;
if(!son[p][0])
{
ans[k]='0';
return k;
}
if(!son[p][1])
{
ans[k]='1';
return k;
}
ans[k]='0';
int end_k=dfs(son[p][0],k+1);
if(end_k!=-1) return end_k;
else
{
ans[k]='1';
end_k=dfs(son[p][1],k+1);
return end_k;
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]=='0') s[j]='1';
else s[j]='0';
add();
}
int end_k=dfs(0,1);
if(end_k==-1) puts("No");
else
{
for(int i=end_k+1;i<=m;i++) ans[i]='0';
puts("Yes"),printf("%s\n",ans+1);
}
return 0;
}