@description@

我们称一组字符串是 “前缀码”,当且仅当不存在一个字符串为另一个字符串的前缀。

现在给定 n 个 01 字符串,其中有些字符串存在最多一个的未知字符。

问是否能将未知字符替换为 0 或 1,使得这 n 个字符串构成 “前缀码”。

Input

第一行给定整数 n 表示字符串个数 (1 ≤ n ≤ 5 · 10^5).

接下来 n 行每行一个字符串,每个字符串由 '0', '1', '?' 构成,且保证最多包含一个 '?'。

保证字符串总长不超过 5 · 10^5.

Output

如果无解,输出 "NO"。

否则输出 "YES",接下来 n 行每行一个字符串(按照输入的顺序输出),表示最后得到的 “前缀码”。

如果有多解,输出任意一个皆可。

Examples

binary.in

4

00?

0?00

?1

1?0

binary.out

YES

000

0100

11

100

binary.in

3

0100

01?0

01?0

binary.out

NO

@solution@

含有问号的串有两种状态,且串 s 选定某个状态时,会导致另一些串只能选择与 s 没有前缀关系的状态。这可以使我们联想到 2-sat。

具体一点,假如 x 与 y 有前缀关系,则 x -> y', y -> x'。

假如 s 不含问号,则我们不妨令 s 表示的串为 x,令 x' -> x 即可。

这样建图是 O(n^2) 的,考虑优化建图。

判断任意两个串的前缀关系,不难想到可以上 trie,则两个串是前缀关系当且仅当两个串在 trie 上对应的结点一个是另一个祖先。

我们建出 trie 后,将 trie 拆成两棵 T1, T2,T1 方向全部朝根结点,T2 方向全部朝叶结点。

则与一个点成前缀关系的点要么顺着 T1 往上,要么顺着 T2 往下。

于是我们可以对于 x 所对应的 trie 中结点 k,k 向 x' 连边,x 向 k 的父亲与儿子连边。

考虑可以新建一个 k',k' 向父亲与儿子连,则 k 所能代表的所有 x 直接向 k 连边即可。

最后一个问题:对于长得完全一样的 x1, x2, ..., xp,我们不能够随便乱连,否则可能会导致 xi -> xi' 的不合法连边。

考虑再新建 y1, y2, ..., yp 表示前缀连边(即 yi 可以直接或间接连向 x1'...xi'),可以通过 yi -> yi-1 且 yi -> xi' 实现;同理得到 z1, z2, ..., zp 表示后缀连边。

则只需要建 xi -> yi-1, xi -> zi+1 即可达到我们的目的。

@accepted code@

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<vector>
  4. #include<algorithm>
  5. using namespace std;
  6. const int MAXN = 1000000;
  7. const int MAXV = 5*MAXN;
  8. vector<int>G[MAXV + 5];
  9. int n, m, ncnt;
  10. void addedge(int u, int v) {G[u].push_back(v);}
  11. int ch[2][MAXN + 5];
  12. vector<int>vec[MAXV + 5];
  13. void insert(char *S, int lenS, int id) {
  14. int nw = 0;
  15. for(int i=0;i<lenS;i++) {
  16. if( ch[S[i] - '0'][nw] == 0 )
  17. ch[S[i] - '0'][nw] = (++ncnt);
  18. nw = ch[S[i] - '0'][nw];
  19. }
  20. vec[nw].push_back(id);
  21. }
  22. void build_trie_edge(int rt, int fa) {
  23. if( !rt ) return ;
  24. addedge(fa + 2*n + 0*(ncnt + 1), rt + 2*n + 0*(ncnt + 1));
  25. addedge(fa + 2*n + 2*(ncnt + 1), rt + 2*n + 0*(ncnt + 1));
  26. addedge(rt + 2*n + 1*(ncnt + 1), fa + 2*n + 1*(ncnt + 1));
  27. addedge(rt + 2*n + 2*(ncnt + 1), fa + 2*n + 1*(ncnt + 1));
  28. for(int i=0;i<vec[rt].size();i++) {
  29. addedge(rt + 2*n + 0*(ncnt + 1), vec[rt][i]^1);
  30. addedge(rt + 2*n + 1*(ncnt + 1), vec[rt][i]^1);
  31. addedge(vec[rt][i], rt + 2*n + 2*(ncnt + 1));
  32. }
  33. build_trie_edge(ch[0][rt], rt);
  34. build_trie_edge(ch[1][rt], rt);
  35. }
  36. void build_node_edge(int rt) {
  37. if( !rt ) return ;
  38. if( vec[rt].size() >= 2 ) {
  39. int lst = vec[rt][0]^1;
  40. for(int i=1;i<vec[rt].size();i++) {
  41. addedge(vec[rt][i], lst);
  42. if( i + 1 == vec[rt].size() ) break;
  43. m++; addedge(m, lst); addedge(m, vec[rt][i]^1);
  44. lst = m;
  45. }
  46. lst = vec[rt][vec[rt].size() - 1]^1;
  47. for(int i=int(vec[rt].size())-2;i>=0;i--) {
  48. addedge(vec[rt][i], lst);
  49. if( i == 0 ) break;
  50. m++; addedge(m, lst); addedge(m, vec[rt][i]^1);
  51. lst = m;
  52. }
  53. }
  54. build_node_edge(ch[0][rt]);
  55. build_node_edge(ch[1][rt]);
  56. }
  57. int tid[MAXV + 5], low[MAXV + 5], num[MAXV + 5], stk[MAXV + 5];
  58. int tp, tot, dcnt;
  59. void dfs(int x) {
  60. stk[++tp] = x; tid[x] = low[x] = (++dcnt);
  61. for(int i=0;i<G[x].size();i++) {
  62. int p = G[x][i];
  63. if( !tid[p] )
  64. dfs(p), low[x] = min(low[x], low[p]);
  65. else if( !num[p] )
  66. low[x] = min(low[x], tid[p]);
  67. }
  68. if( low[x] >= tid[x] ) {
  69. tot++;
  70. while( tp && tid[stk[tp]] >= tid[x] ) {
  71. int t = stk[tp--];
  72. num[t] = tot, vec[tot].push_back(t);
  73. }
  74. }
  75. }
  76. bool tag[MAXV + 5];
  77. void solve() {
  78. for(int i=1;i<=tot;i++) {
  79. for(int j=0;j<vec[i].size();j++) {
  80. int x = vec[i][j];
  81. for(int k=0;k<G[x].size();k++)
  82. if( tag[num[G[x][k]]] )
  83. tag[i] = true;
  84. }
  85. if( !tag[i] ) {
  86. for(int j=0;j<vec[i].size();j++) {
  87. int x = vec[i][j];
  88. if( x < 2*n )
  89. tag[num[x^1]] = true;
  90. }
  91. }
  92. }
  93. }
  94. char str[MAXN + 5]; int len[MAXN + 5];
  95. int main() {
  96. freopen("binary.in", "r", stdin);
  97. freopen("binary.out", "w", stdout);
  98. scanf("%d", &n);
  99. for(int i=1;i<=n;i++) {
  100. scanf("%s", str + len[i-1]);
  101. len[i] = len[i-1] + strlen(str + len[i-1]);
  102. }
  103. for(int i=1;i<=n;i++) {
  104. int pos = -1;
  105. for(int j=len[i-1];j<len[i];j++)
  106. if( str[j] == '?' ) pos = j;
  107. if( pos == -1 ) {
  108. addedge((i-1)<<1|1, (i-1)<<1|0);
  109. insert(str + len[i-1], len[i] - len[i-1], (i-1)<<1|0);
  110. }
  111. else {
  112. str[pos] = '0', insert(str + len[i-1], len[i] - len[i-1], (i-1)<<1|0);
  113. str[pos] = '1', insert(str + len[i-1], len[i] - len[i-1], (i-1)<<1|1);
  114. str[pos] = '?';
  115. }
  116. }
  117. m = 2*n + 3*(ncnt + 1);
  118. build_trie_edge(ch[0][0], 0), build_trie_edge(ch[1][0], 0);
  119. build_node_edge(ch[0][0]), build_node_edge(ch[1][0]);
  120. for(int i=0;i<=ncnt;i++) vec[i].clear();
  121. for(int i=0;i<=m;i++)
  122. if( !tid[i] ) dfs(i);
  123. for(int i=0;i<n;i++)
  124. if( num[i<<1] == num[i<<1|1] ) {
  125. puts("NO");
  126. return 0;
  127. }
  128. puts("YES"); solve();
  129. for(int i=1;i<=n;i++)
  130. for(int j=len[i-1];j<len[i];j++)
  131. if( str[j] == '?' )
  132. str[j] = tag[num[(i-1)<<1]] + '0';
  133. for(int i=1;i<=n;i++) {
  134. for(int j=len[i-1];j<len[i];j++)
  135. putchar(str[j]);
  136. puts("");
  137. }
  138. }

@details@

一开始 RE 了,非常懵逼。

后来把 trie 大小稍微调整了一下,发现MLE了又再把2-sat的图的点数调到一个感觉不够的大小,结果 A 了。

思考了一下,发现原来我每次加入字符串是两个两个加的,所以 trie 的大小应该开到 2 倍字符串总长。。。

另外,原来 tarjan 求出来的强连通的编号就是天然的拓扑序。

我以前还一直在写什么拓扑排序。。。原来拓扑排序没用啊。。。

2-sat 用拓扑排序求出来的方案数是非常“任意”的——即它既没有字典序也没有任何已知规律。

@gym - 101190B@ Binary Code的更多相关文章

  1. Codeforces Gym 100015H Hidden Code 暴力

    Hidden Code 题目连接: http://codeforces.com/gym/100015/attachments Description It's time to put your hac ...

  2. Codeforces Gym 100431B Binary Search 搜索+组合数学+高精度

    原题链接:http://codeforces.com/gym/100431/attachments/download/2421/20092010-winter-petrozavodsk-camp-an ...

  3. BZOJ4840 NEERC2016 Binary Code

    Problem BZOJ Solution 可能是因为快要省选了,所以最近更博的频率好像高了点_(:зゝ∠)_ 每个字符串最多有两个状态,然后要满足一些依赖关系,考虑2sat.可以先把字符串的结束节点 ...

  4. codeforces gym #101161G - Binary Strings(矩阵快速幂,前缀斐波那契)

    题目链接: http://codeforces.com/gym/101161/attachments 题意: $T$组数据 每组数据包含$L,R,K$ 计算$\sum_{k|n}^{}F(n)$ 定义 ...

  5. 格雷码(Gray Code)转二进制码(Binary Code)

    学习verilog generate语句时,偶然看到用generate语句来进行格雷码到二进制码转换的代码,就从网上找了一些案例来学习. 下表为几种自然二进制码与格雷码的对照表: 十进制数 自然二进制 ...

  6. USACO Party Lamps 【Binary code solvution】【规律】

    写这道题目的时候遇到了一个令人诧异的问题,就是平台上跑来的结果和我本机跑起来的结果不一样. 后来Debug了之后才发现是我数组开小了,只开到100 的数组竟然都去访问他170位的地址肯定要跪成翔啊.. ...

  7. Gym - 100801H Hash Code Hacker (构造)

    题意:求 n 个哈希值相同的串. 析:直接构造,通过取模来查找相同的串. 代码如下: #pragma comment(linker, "/STACK:1024000000,102400000 ...

  8. Gym - 101987G Secret Code (概率+数学积分)

    题意:有A,B,C三个人要见面,每个人在[0,S]随机选择一个时间点作为见面时间,先到的那个人要等下一个人来了之后和他确认信息,然后马上就走. 例如,假如A先到,B其次,C最后到,那么A要等B到了之后 ...

  9. Adaptive Code Via C#读书笔记

    原书链接: http://www.amazon.com/Adaptive-Code-via-principles-Developer-ebook/dp/B00OCLLYTY/ref=dp_kinw_s ...

随机推荐

  1. mysql与hibernate选择某个字段的最大值,比如表中的最大id

    hibernate public int getMaxId(Session session) { String hql = "SELECT MAX(id) FROM ArticleModel ...

  2. centos 安装nginx + 多个tomcat负载均衡

    今天在centos上安装了两个tomcat和nginx,进行配置.今天记录的只是最基本的实现测试.(不包含使用redis进行session共享) Nginx 是一款轻量级的Web 服务器/反向代理服务 ...

  3. day37 05-HIbernate二级缓存:一级缓存更新同步到二级缓存及二级缓存配置文件

    一级缓存的更新会自动同步到二级缓存. @SuppressWarnings("all") @Test // 将内存中的数据写到硬盘 public void demo7(){ Sess ...

  4. HDU 4280 Island Transport(dinic+当前弧优化)

    Island Transport Description In the vast waters far far away, there are many islands. People are liv ...

  5. 如何查看MySQL执行计划呢?

    覆盖索引: MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件 包含所有满足查询需要的数据的索引称为 覆盖索引(Covering Index) 如果要使用覆盖索引,一定 ...

  6. jquery Select2 学习笔记之中文提示 - CSDN博客

    首先学习这个东西呢,还是看官网比较全面 select2官网例子 要select2中文显示:必须要引入中文包,且一定要放在select2.js之后 [javascript] view plain cop ...

  7. 访问Bing地图

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  8. Sql server定时执行某个sql 通过Windows 计划任务(非代理Job方式)

    建立 bat文件.内容如下: osql -s "xxx.xxx.xx.x" -U sa -P sa -d DB -i TruncateSql.sql osql -S "l ...

  9. go struct 工厂

  10. Vue 实现展开折叠效果

    Vue 实现展开折叠效果 效果参见:https://segmentfault.com/q/1010000011359250/a-1020000011360185 上述链接中,大佬给除了解决方法,再次进 ...