@gym - 101190B@ Binary Code
@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@
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 1000000;
const int MAXV = 5*MAXN;
vector<int>G[MAXV + 5];
int n, m, ncnt;
void addedge(int u, int v) {G[u].push_back(v);}
int ch[2][MAXN + 5];
vector<int>vec[MAXV + 5];
void insert(char *S, int lenS, int id) {
int nw = 0;
for(int i=0;i<lenS;i++) {
if( ch[S[i] - '0'][nw] == 0 )
ch[S[i] - '0'][nw] = (++ncnt);
nw = ch[S[i] - '0'][nw];
}
vec[nw].push_back(id);
}
void build_trie_edge(int rt, int fa) {
if( !rt ) return ;
addedge(fa + 2*n + 0*(ncnt + 1), rt + 2*n + 0*(ncnt + 1));
addedge(fa + 2*n + 2*(ncnt + 1), rt + 2*n + 0*(ncnt + 1));
addedge(rt + 2*n + 1*(ncnt + 1), fa + 2*n + 1*(ncnt + 1));
addedge(rt + 2*n + 2*(ncnt + 1), fa + 2*n + 1*(ncnt + 1));
for(int i=0;i<vec[rt].size();i++) {
addedge(rt + 2*n + 0*(ncnt + 1), vec[rt][i]^1);
addedge(rt + 2*n + 1*(ncnt + 1), vec[rt][i]^1);
addedge(vec[rt][i], rt + 2*n + 2*(ncnt + 1));
}
build_trie_edge(ch[0][rt], rt);
build_trie_edge(ch[1][rt], rt);
}
void build_node_edge(int rt) {
if( !rt ) return ;
if( vec[rt].size() >= 2 ) {
int lst = vec[rt][0]^1;
for(int i=1;i<vec[rt].size();i++) {
addedge(vec[rt][i], lst);
if( i + 1 == vec[rt].size() ) break;
m++; addedge(m, lst); addedge(m, vec[rt][i]^1);
lst = m;
}
lst = vec[rt][vec[rt].size() - 1]^1;
for(int i=int(vec[rt].size())-2;i>=0;i--) {
addedge(vec[rt][i], lst);
if( i == 0 ) break;
m++; addedge(m, lst); addedge(m, vec[rt][i]^1);
lst = m;
}
}
build_node_edge(ch[0][rt]);
build_node_edge(ch[1][rt]);
}
int tid[MAXV + 5], low[MAXV + 5], num[MAXV + 5], stk[MAXV + 5];
int tp, tot, dcnt;
void dfs(int x) {
stk[++tp] = x; tid[x] = low[x] = (++dcnt);
for(int i=0;i<G[x].size();i++) {
int p = G[x][i];
if( !tid[p] )
dfs(p), low[x] = min(low[x], low[p]);
else if( !num[p] )
low[x] = min(low[x], tid[p]);
}
if( low[x] >= tid[x] ) {
tot++;
while( tp && tid[stk[tp]] >= tid[x] ) {
int t = stk[tp--];
num[t] = tot, vec[tot].push_back(t);
}
}
}
bool tag[MAXV + 5];
void solve() {
for(int i=1;i<=tot;i++) {
for(int j=0;j<vec[i].size();j++) {
int x = vec[i][j];
for(int k=0;k<G[x].size();k++)
if( tag[num[G[x][k]]] )
tag[i] = true;
}
if( !tag[i] ) {
for(int j=0;j<vec[i].size();j++) {
int x = vec[i][j];
if( x < 2*n )
tag[num[x^1]] = true;
}
}
}
}
char str[MAXN + 5]; int len[MAXN + 5];
int main() {
freopen("binary.in", "r", stdin);
freopen("binary.out", "w", stdout);
scanf("%d", &n);
for(int i=1;i<=n;i++) {
scanf("%s", str + len[i-1]);
len[i] = len[i-1] + strlen(str + len[i-1]);
}
for(int i=1;i<=n;i++) {
int pos = -1;
for(int j=len[i-1];j<len[i];j++)
if( str[j] == '?' ) pos = j;
if( pos == -1 ) {
addedge((i-1)<<1|1, (i-1)<<1|0);
insert(str + len[i-1], len[i] - len[i-1], (i-1)<<1|0);
}
else {
str[pos] = '0', insert(str + len[i-1], len[i] - len[i-1], (i-1)<<1|0);
str[pos] = '1', insert(str + len[i-1], len[i] - len[i-1], (i-1)<<1|1);
str[pos] = '?';
}
}
m = 2*n + 3*(ncnt + 1);
build_trie_edge(ch[0][0], 0), build_trie_edge(ch[1][0], 0);
build_node_edge(ch[0][0]), build_node_edge(ch[1][0]);
for(int i=0;i<=ncnt;i++) vec[i].clear();
for(int i=0;i<=m;i++)
if( !tid[i] ) dfs(i);
for(int i=0;i<n;i++)
if( num[i<<1] == num[i<<1|1] ) {
puts("NO");
return 0;
}
puts("YES"); solve();
for(int i=1;i<=n;i++)
for(int j=len[i-1];j<len[i];j++)
if( str[j] == '?' )
str[j] = tag[num[(i-1)<<1]] + '0';
for(int i=1;i<=n;i++) {
for(int j=len[i-1];j<len[i];j++)
putchar(str[j]);
puts("");
}
}
@details@
一开始 RE 了,非常懵逼。
后来把 trie 大小稍微调整了一下,发现MLE了又再把2-sat的图的点数调到一个感觉不够的大小,结果 A 了。
思考了一下,发现原来我每次加入字符串是两个两个加的,所以 trie 的大小应该开到 2 倍字符串总长。。。
另外,原来 tarjan 求出来的强连通的编号就是天然的拓扑序。
我以前还一直在写什么拓扑排序。。。原来拓扑排序没用啊。。。
2-sat 用拓扑排序求出来的方案数是非常“任意”的——即它既没有字典序也没有任何已知规律。
@gym - 101190B@ Binary Code的更多相关文章
- Codeforces Gym 100015H Hidden Code 暴力
Hidden Code 题目连接: http://codeforces.com/gym/100015/attachments Description It's time to put your hac ...
- Codeforces Gym 100431B Binary Search 搜索+组合数学+高精度
原题链接:http://codeforces.com/gym/100431/attachments/download/2421/20092010-winter-petrozavodsk-camp-an ...
- BZOJ4840 NEERC2016 Binary Code
Problem BZOJ Solution 可能是因为快要省选了,所以最近更博的频率好像高了点_(:зゝ∠)_ 每个字符串最多有两个状态,然后要满足一些依赖关系,考虑2sat.可以先把字符串的结束节点 ...
- codeforces gym #101161G - Binary Strings(矩阵快速幂,前缀斐波那契)
题目链接: http://codeforces.com/gym/101161/attachments 题意: $T$组数据 每组数据包含$L,R,K$ 计算$\sum_{k|n}^{}F(n)$ 定义 ...
- 格雷码(Gray Code)转二进制码(Binary Code)
学习verilog generate语句时,偶然看到用generate语句来进行格雷码到二进制码转换的代码,就从网上找了一些案例来学习. 下表为几种自然二进制码与格雷码的对照表: 十进制数 自然二进制 ...
- USACO Party Lamps 【Binary code solvution】【规律】
写这道题目的时候遇到了一个令人诧异的问题,就是平台上跑来的结果和我本机跑起来的结果不一样. 后来Debug了之后才发现是我数组开小了,只开到100 的数组竟然都去访问他170位的地址肯定要跪成翔啊.. ...
- Gym - 100801H Hash Code Hacker (构造)
题意:求 n 个哈希值相同的串. 析:直接构造,通过取模来查找相同的串. 代码如下: #pragma comment(linker, "/STACK:1024000000,102400000 ...
- Gym - 101987G Secret Code (概率+数学积分)
题意:有A,B,C三个人要见面,每个人在[0,S]随机选择一个时间点作为见面时间,先到的那个人要等下一个人来了之后和他确认信息,然后马上就走. 例如,假如A先到,B其次,C最后到,那么A要等B到了之后 ...
- Adaptive Code Via C#读书笔记
原书链接: http://www.amazon.com/Adaptive-Code-via-principles-Developer-ebook/dp/B00OCLLYTY/ref=dp_kinw_s ...
随机推荐
- idea中隐藏.idea文件夹和.iml文件
idea中的.idea文件夹和.iml是平常几乎不使用的文件,在创建父子工程或者聚合工程时反而会对我们操作产生干扰,所以,一般情况下,我们都将其隐藏掉,步骤如下: 操作前: 具体操作:File——&g ...
- htmlunit第一个爬虫演示 目标网址http://ent.sina.com.cn/film/
基本都要放弃了 springmvc 配置了htmlunit之后无法运行,都不能正常实例化webclient,但是突然想起来用maven应用程序测试一下 结果竟然就可以了.好吧,还是有希望的 大佬博客 ...
- ifconfig命令为centos linux系统配置临时的局域名IP、网关以及子网掩码
ifconfig eth0 192.168.1.25 netmask 255.255.255.0 broadcast 192.168.1.1 up netmask:子网掩码broadcast:默认网关
- 中介者模式(Mediator、ConcreteMediator、Colleague Class)(租房中介)
中介者模式就是利用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地互相引用,从而使其耦合松散,而且可以独立地改变他们之间的交互. 就像租房的中介系统,房主跟租房者不需要知道彼此只需要,只 ...
- python基础--迭代器、生成器、内置函数、面向对象编程
迭代器:迭代器对象从集合的第一个元素开始访问,直到所有的元素都被访问完结束.迭代器只能往前不会后退 迭代:更新换代(重复)的过程,每次的迭代都必须基于上一次的结果 迭代器:迭代取值的工具 使用迭代器的 ...
- 2019.9.29 csp-s模拟测试55 反思总结
不咕咕咕是一种美德[大雾] 头一次体会到爆肝写题解??? 这次考试我们没赶上,是后来掐着时间每个人自己考的.我最后的分数能拿到152…熟悉的一题AC两题爆炸. 强烈吐槽出题人起名走心 T1联: 发现每 ...
- 查漏补缺·补丁计划
趁着神志清醒赶紧写一下. 多次考试暴露出各种问题.新的知识点先不去搞了,最近多做一些不擅长的类型的题查漏补缺一下吧. 唔,首先是比较考验思维的类型,我智商太低又刷题少不会什么套路,只能最近赶紧赶一下进 ...
- Laravel 5.2 使用 JWT 完成多用户认证 | Laravel China 社区 - 高品质的 Laravel 开发者社区 - Powered by PHPHub
Json Web Token# JWT代表Json Web Token.JWT能有效地进行身份验证并连接前后端. 降地耦合性,取代session,进一步实现前后端分离 减少服务器的压力 可以很简单的实 ...
- 100个常用的原生JavaScript函数
1.原生JavaScript实现字符串长度截取 复制代码代码如下: function cutstr(str, len) { var temp; var icount = 0; var ...
- 模拟15 题解(waiting)
T1 60%算法 定义f[i][j]表示枚举到i位置,已经使用过了j个队, $f[i][j]+=f[i-1][t] ( t \in [max(0,j-k),j])$滚动一下 这是个O(n^3)的,考虑 ...