LOJ6036 编码 2-SAT、Trie
每个串只有一个?,?还只能填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\)个串填入0或1之后是否得到当前串,是为\(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的更多相关文章
- LOJ6036编码
每个串拆成两个,都插入trie数. 把trie树建出来后,每一条从根到叶子的链上最多只能有一个变量为1. 这是个经典的前后缀优化2-sat建图的套路. 树上的做法也就是边dfs边做而已. #inclu ...
- 数据结构与算法简记--Trie树
Trie树 概念 多叉树,节点为字符串中的单个字符. Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起. 将多个字符串按字符拆分插入Trie树,用于字符串查找,关键词提示等 举 ...
- [LOJ6029~6052]雅礼集训 2017 选做
Link 代码可以在loj上看我的提交记录. Day 1 [LOJ6029]市场 对于一次除法操作,若区间内所有数的减少量均相同则可视作区间减法,否则暴力递归下去.显然一个线段树节点只会被暴力递归进去 ...
- 前端笔记之服务器&Ajax(上)服务器&PHP&数据交互&HTTP
一.服务器 1.1 什么是服务器,做什么的? 服务器,就是放在机房中的电脑,和我们的电脑的区别在与服务器有固定的IP,服务器的安全性和稳定性相当的高;性能一般就可以了,但是CPU的性能要比普通的客户机 ...
- 【LOJ6036】编码(2-sat)
[LOJ6036]编码(2-sat) 题面 LOJ 题解 很显然的一个暴力: 枚举每个串中的?是什么,然后把和它有前缀关系的串全部给找出来,不合法的连边处理一下,那么直接跑\(2-sat\)就做完了. ...
- 51Nod1601 完全图的最小生成树计数 Trie Prufer编码
原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1601.html 题目传送门 - 51Nod1601 题意 题解 首先我们考虑如何求答案. 我们将所有 ...
- 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)
前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...
- 【LOJ6036】 「雅礼集训 2017 Day4」编码
传送门 LOJ Solution 因为?只有两种可能为0,1,所以就把这两个串搞出来. 那么现在?取0和?取1不能并存,前缀不能并存,所以就是一个\(2-SAT\),现在问题在于这个东西可能会有很多条 ...
- LOJ #6036.「雅礼集训 2017 Day4」编码 Trie树上2-sat
记得之前做过几道2-sat裸体,以及几道2-sat前缀优化建图,这道题使用了前缀树上前缀树优化建图.我们暴力建图肯定是n^2级别的,那么我们要是想让边数少点,就得使用一些骚操作.我们观察我们的限制条件 ...
随机推荐
- 本机mysql 5.7服务启动后停止,某些服务在未有其他应用程序使用时停止
本机mysql 5.7服务启动后停止,某些服务在未有其他应用程序使用时停止 出现这种报错,mysql服务启动不了: 错误的尝试: 1:尝试了这个博客:https://blog.csdn.net/wai ...
- (后端)JackSon将java对象转换为JSON字符串(转)
转载小金金金丶园友: JackSon可以将java对象转换为JSON字符串,步骤如下: 1.导入JackSon 的jar包 2.创建ObjectMapper对象 3.使用ObjectMapper对象的 ...
- eclipse配置环境变量 (特别是输入javac无显示问题)
下载JDK:http://www.oracle.com/technetwork/java/javase/downloads/index.html 最近win10恢复了一下系统,重新给eclipse配一 ...
- 使用Visual Studio Team Services持续集成(二)——为构建定义属性
使用Visual Studio Team Services持续集成(二)--为构建定义属性 1.从VSTS帐户进入到Build 2.编辑构建定义并单击Options Description:如果这里明 ...
- request获取各种路径
equest.getRealPath() 这个方法已经不推荐使用了,代替方法是: request.getSession().getServletContext().getRealPath() 在ser ...
- c/c++ 类模板初探
类模板 1,模板类里的函数都是模板函数 2,模板类里的函数,在类外面实现的时候,要用模板函数(方法:push_back)的方式实现,在类内部实现时,不需要用模板函数(方法:show)方式实现. 3,用 ...
- git 使用命令删除远程分支和本地分支
删除远程分支命令: git push origin :<远程分支名称> git push origin --delete <远程分支名称> 删除本地分支: git bran ...
- IPerf——网络测试工具介绍与源码解析(3)
[线程的生成] 生成线程时需要传入一个thread_Settings类型的变量,thread_Settings包含所有线程运行时需要的信息,命令行选项参数解析后所有得到的属性都存储到该类型的变量中 ...
- LeetCode算法题-Third Maximum Number(Java实现-四种解法)
这是悦乐书的第222次更新,第235篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第89题(顺位题号是414).给定非空的整数数组,返回此数组中的第三个最大数字.如果不存 ...
- LeetCode算法题-Palindrome Linked List(Java实现)
这是悦乐书的第196次更新,第202篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第58题(顺位题号是234).给出一个单链表,确定它是否是回文.例如: 输入:1-> ...