传送门


每个串只有一个??还只能填0或者1,不难想到2-SAT求解。

一个很暴力的想法是枚举?0或者1,然后对所有可能的前缀连边。这样边数是\(O(n^2)\)的,需要优化。

看到前缀不难想到Trie树。将所有串的所有可能形态填入Trie树中,然后使用前缀后缀优化2-SAT连边的方式优化连边。

具体来说对于每一个串开两个点表示?0还是1,对于Trie树上每一个串的结束节点也开两个点,表示这个点及其所有前缀中是否存在已经选过的串。

连边考虑一些互为前缀的串。设串为\(s_1,s_2,s_3,...,s_k\),第\(i\)个串在Trie树上的节点的\(01\)变量为\(bool[i][0/1]\),第\(i\)个节点对应串的\(01\)变量为\(belong[i][0/1]\)(为了好描述,这里定义的\(belong[i][0/1]\)表示第\(i\)个串填入01之后是否得到当前串,是为\(1\))

那么有边

\(belong[i][1] \rightarrow bool[i][1]\)

\(bool[i][0] \rightarrow bool[i -1][0]\)

\(bool[i][1] \rightarrow bool[i + 1][1]\)

\(bool[i][0] \rightarrow belong[i][0]\)

\(bool[i][1] \rightarrow belong[i + 1][0]\)

这些边可以在建Trie的过程中直接建。记得要建逆否命题的边。然后跑一遍缩点就行了

细节:①开始要将字符串按长度从小到大排序,才可以保证上面方法的正确性;②可能存在某些串相等,建Trie的时候要特别注意。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
#include<vector>
#define INF 0x3f3f3f3f
//This code is written by Itst
using namespace std; const int MAXN = 3e6 + 3;
struct Edge{
int end , upEd;
}Ed[MAXN << 3];
int head[MAXN] , N , cntN = 1 , cntEd; inline void addEd(int a , int b){
Ed[++cntEd] = (Edge){b , head[a]};
head[a] = cntEd;
} namespace Trie{
int ch[MAXN][2] , ind[MAXN] , cnt = 1; void insert(string s , int bl){
int cur = 1 , up = 0;
for(auto c : s){
if(!ch[cur][c - '0'])
ch[cur][c - '0'] = ++cnt;
cur = ch[cur][c - '0'];
if(ind[cur]) up = ind[cur];
}
cntN += 2;
addEd(bl , cntN); addEd(cntN ^ 1 , bl ^ 1);
if(up){
addEd(up , cntN); addEd(cntN ^ 1 , up ^ 1);
addEd(up , bl ^ 1); addEd(bl , up ^ 1);
}
ind[cur] = cntN;
}
}
using Trie::insert; int stk[MAXN] , dfn[MAXN] , low[MAXN] , in[MAXN];
int top , ts , cntSCC;
bool vis[MAXN] , ins[MAXN]; void pop(int x){
++cntSCC;
do{
in[stk[top]] = cntSCC;
ins[stk[top]] = 0;
}while(stk[top--] != x);
} void tarjan(int x , int p){
vis[x] = ins[x] = 1;
stk[++top] = x;
dfn[x] = low[x] = ++ts;
for(int i = head[x] ; i ; i = Ed[i].upEd){
if(!vis[Ed[i].end]) tarjan(Ed[i].end , x);
else if(!ins[Ed[i].end]) continue;
low[x] = min(low[x] , low[Ed[i].end]);
}
if(dfn[x] == low[x]) pop(x);
} vector < string > str; bool cmp(string a , string b){return a.size() < b.size();} int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
cin >> N;
for(int i = 1 ; i <= N ; ++i){
string s;
cin >> s;
str.push_back(s);
}
sort(str.begin() , str.end() , cmp);
for(auto t : str){
cntN += 2;
int nd = cntN , pos = t.find('?');
if(pos != string::npos){
t[pos] = '0';
insert(t , nd - 1);
t[pos] = '1';
insert(t , nd);
}
else{
insert(t , nd);
addEd(nd - 1 , nd);
}
}
for(int i = 2 ; i <= cntN ; ++i)
if(!vis[i]) tarjan(i , 0);
for(int i = 2 ; i <= cntN ; i += 2)
if(in[i] == in[i + 1])
return puts("NO") , 0;
puts("YES");
return 0;
}

LOJ6036 编码 2-SAT、Trie的更多相关文章

  1. LOJ6036编码

    每个串拆成两个,都插入trie数. 把trie树建出来后,每一条从根到叶子的链上最多只能有一个变量为1. 这是个经典的前后缀优化2-sat建图的套路. 树上的做法也就是边dfs边做而已. #inclu ...

  2. 数据结构与算法简记--Trie树

    Trie树 概念 多叉树,节点为字符串中的单个字符. Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起. 将多个字符串按字符拆分插入Trie树,用于字符串查找,关键词提示等 举 ...

  3. [LOJ6029~6052]雅礼集训 2017 选做

    Link 代码可以在loj上看我的提交记录. Day 1 [LOJ6029]市场 对于一次除法操作,若区间内所有数的减少量均相同则可视作区间减法,否则暴力递归下去.显然一个线段树节点只会被暴力递归进去 ...

  4. 前端笔记之服务器&Ajax(上)服务器&PHP&数据交互&HTTP

    一.服务器 1.1 什么是服务器,做什么的? 服务器,就是放在机房中的电脑,和我们的电脑的区别在与服务器有固定的IP,服务器的安全性和稳定性相当的高;性能一般就可以了,但是CPU的性能要比普通的客户机 ...

  5. 【LOJ6036】编码(2-sat)

    [LOJ6036]编码(2-sat) 题面 LOJ 题解 很显然的一个暴力: 枚举每个串中的?是什么,然后把和它有前缀关系的串全部给找出来,不合法的连边处理一下,那么直接跑\(2-sat\)就做完了. ...

  6. 51Nod1601 完全图的最小生成树计数 Trie Prufer编码

    原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1601.html 题目传送门 - 51Nod1601 题意 题解 首先我们考虑如何求答案. 我们将所有 ...

  7. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  8. 【LOJ6036】 「雅礼集训 2017 Day4」编码

    传送门 LOJ Solution 因为?只有两种可能为0,1,所以就把这两个串搞出来. 那么现在?取0和?取1不能并存,前缀不能并存,所以就是一个\(2-SAT\),现在问题在于这个东西可能会有很多条 ...

  9. LOJ #6036.「雅礼集训 2017 Day4」编码 Trie树上2-sat

    记得之前做过几道2-sat裸体,以及几道2-sat前缀优化建图,这道题使用了前缀树上前缀树优化建图.我们暴力建图肯定是n^2级别的,那么我们要是想让边数少点,就得使用一些骚操作.我们观察我们的限制条件 ...

随机推荐

  1. Android 基本控件的常用属性

    TextView //normal 默认 bold 粗体 italic斜体 可用| 多选 android:textStyle //设置限定可以输入哪些字符 android:digits //设置文本可 ...

  2. Python笔记(十六):迭代器

    (一)iterable对象和Iterator对象的区别 iterable对象(可迭代的对象):可以使用for循环,例如:字符串.列表 .字典 .集合等 Iterator对象(迭代器):除了可以用for ...

  3. DBA思考系列——学会拒绝不合理的需求

    DBA思考系列--学会拒绝不合理的需求   一直以来,个性都比较随意,一般很少拒绝开发人员的一些需求(有点老好人的感觉). 这点一直被老大诟病,也一直在反省!最近又有一件事情,让我觉得:应该学会拒绝不 ...

  4. RMAN命令DELETE操作总结

    本篇总结一下RMAN命令中的DELETE操作,DELETE命令用于删除RMAN备份记录以及相应的物理文件. To delete physical backups and copies as well ...

  5. Spring MVC 实现文件的上传和下载 (八)

    完整的项目案例: springmvc.zip 目录 SpringMVC 中,文件的上传,是通过 MultipartResolver 实现的. 所以,如果要实现文件的上传,只要在 spring-mvc. ...

  6. 孟岩:通证(token)和通证经济的目的在于改善现有经济的效率性

    孟岩是最早将token翻译成为通证的区块链大咖,这个翻译已经得到到了越来越人的认可.原来它叫代币,孟岩建议把它翻译成通证.以下是孟岩关于通证的注解. (孟岩,柏链道捷CEO,CSDN副总裁,区块链通证 ...

  7. TNS-12535: TNS:operation timed out

    AWS数据库云服务器出现了连接超时的错误,于是查看相关时段的alert日志,发现了如下的错误: **************************************************** ...

  8. Linux学习历程——Centos 7 man命令

    一.man命令介绍 man,为单词manual的缩写,是linux下的帮助指令. 二.实例 以man命令为例,输入 man  man  获取man命令的帮助文档 可以看出,使用man命令查询到的帮助信 ...

  9. Windows Server 2016-域站点链接及复制时间调整

    本章简单为大家介绍如何新建域链接并调整复制计划.生产环境中很多情况下需要我们手工去创建站点复制链接,并根据实际带宽情况调整复制计划以减轻网络压力等.站点内部署多台域控制器,域控制器间的 复制链接建议通 ...

  10. MySQL注入与防御

    1.简介 1.1.含义 在一个应用中,数据的安全无疑是最重要的.数据的最终归宿都是数据库,因此如何保证数据库不被恶意攻击者入侵是一项重要且严肃的问题! SQL注入作为一种很流行的攻击手段,一直以来都受 ...