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级别的,那么我们要是想让边数少点,就得使用一些骚操作.我们观察我们的限制条件 ...
随机推荐
- Flutter 布局(二)- Padding、Align、Center详解
本文主要介绍Flutter布局中的Padding.Align以及Center控件,详细介绍了其布局行为以及使用场景,并对源码进行了分析. 1. Padding A widget that insets ...
- (网页)websocket例子
转载自博客园张果package action; import javax.websocket.CloseReason; import javax.websocket.OnClose; import j ...
- HTMLTestRunner修改成Python3版本
修改前:HTMLTestRunner下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html BSTestRunner 下载地址:htt ...
- ajax参数
$.ajax({ type: "GET", url: "Login.ashx", dataType: "text", cache: fals ...
- mssql sqlserver 判断字符串大小写的方法分享
摘要:下文讲述使用sql脚本的方法判断字符串为大小写的方法分享,如下所示 实验环境:sqlserver 2008 R2 实现思路: 将字符串转换为大写或小写然后转换为二进制编码, 然后和源字符串做对比 ...
- Spring基于注解注入的两种方式
1.@Autowried 1)默认基于类型查找容器的的Bean进行注入(注入的Bean的实现类是唯一的). 2)当实现类的Bean大于一个的时候,需结合@Qualifier,根据Bean的名称来指定需 ...
- 安装Jenkins getting started卡住
前言 jenkins版本:2.32.3 操作系统:windows 卡住信息 如果在安装jenkins时卡在getting startted的界面,如下所示 解决方法 1.打开 运行 输入 servi ...
- 【Git学习一】Git 初始化
在开始Git之旅之前,我们需要设置一下Git的配置变量. 1.告诉Git当前用户的姓名和邮件地址,配置用户名和邮件地址将在版本库提交时用到. 例子: ------------------------- ...
- 为爱好舞蹈的人们做的软件,细究数据结构,操作系统,磁盘原理,用java/c/c++写一个开源 MP3助手
1.可以给歌曲间插播空白音乐 2.拖拽式调整 3.先排序,后一键写入顺序文件. 国外的开源软件 MP3 播放排序 http://www.murraymoffatt.com/software-prob ...
- C++ 中operator用法:隐式类型转换
[转]C++ operator两种用法 C++,有时它的确是个耐玩的东东,就比如operator,它有两种用法,一种是operator overloading(操作符重载),一种是operator c ...