记得之前做过几道2-sat裸体,以及几道2-sat前缀优化建图,这道题使用了前缀树上前缀树优化建图.
我们暴力建图肯定是n^2级别的,那么我们要是想让边数少点,就得使用一些骚操作.
我们观察我们的限制条件,不就是选了一个点,那么这个点的前缀都不能选吗(选了一个点,以他为前缀的的点也不能选,这个限制条件可以通过前面那个限制条件体现出来,所以说观察到问题本质是一样的,可以简化我们的问题).那么我们就可以在Trie上建图,使得选择一个点,那么他的前缀点都必须不能选,就可以了.但是对于一个点上有多个点的情况,我们要特殊处理,我的处理方法是,把那些点拽出来作为树点.
最后说一下,要注意2-sat建图一定要连逆否命题边.
(感觉自己2-sat好虚啊……)
语言笔记:
exit(0),只要你在程序中使用,无论在哪里,直接正常退出,具体情况见http://blog.csdn.net/u010046690/article/details/47105665

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=;
struct V{
int to,next;
}c[N<<];
int head[N<<],t;
inline void add(int x,int y){
c[++t].to=y,c[t].next=head[x],head[x]=t;
}
char s[N],*begin[N];
int n,len[N],m;
int pos[N],temp[N];
int dfn[N<<],low[N<<],belong[N<<],stack[N<<],top,num,Ti;
bool in[N<<];
inline void Tarjan(int x){
dfn[x]=low[x]=++Ti;
stack[++top]=x;
in[x]=true;
register int i;
for(i=head[x];i;i=c[i].next)
if(!dfn[c[i].to]){
Tarjan(c[i].to);
low[x]=std::min(low[x],low[c[i].to]);
}else if(in[c[i].to])
low[x]=std::min(low[x],dfn[c[i].to]);
if(low[x]==dfn[x]){
++num;
register int j;
do{
j=stack[top--];
in[j]=false;
belong[j]=num;
}while(j!=x);
}
}
#define choose(a,b) (((a)<<1)-(b))
struct Trie{
Trie *ch[];
std::vector<int> mem;
Trie(){ch[]=ch[]=NULL,mem.clear();}
inline void* operator new(size_t);
}*root,*C,*mempool;
inline void* Trie::operator new(size_t){
if(C==mempool){
C=new Trie[(<<)+];
mempool=C+(<<)+;
}
return C++;
}
inline void build(Trie *p,int id){
register int i,x,a,b,size=p->mem.size();
if(!size)return;
for(i=;i<size;++i){
x=p->mem[i];
if((pos[x]==-&&pos[id]==-)||(pos[x]==-&&pos[id]>=len[x])){
puts("NO");
exit();
}
if(pos[x]==pos[id]){
add(choose(x,),choose(id,));
add(choose(x,),choose(id,));
add(choose(id,),choose(x,));
add(choose(id,),choose(x,));
}else{
if(pos[id]==-||pos[id]>=len[x]){
if(begin[id][pos[x]]==''){
add(choose(x,),choose(x,));
}else{
add(choose(x,),choose(x,));
}
}else{
if(pos[x]==-){
if(begin[x][pos[id]]==''){
add(choose(id,),choose(id,));
}else{
add(choose(id,),choose(id,));
}
}else{
a=begin[id][pos[x]]=='';
b=begin[x][pos[id]]=='';
add(choose(x,a),choose(id,b^));
add(choose(id,b),choose(x,a^));
}
}
}
}
}
inline void insert(int id){
register Trie *p=root,*w;
register int i,j,l=len[id];
for(i=;i<l;++i){
if(begin[id][i]=='?'){
if(!p->ch[])
p->ch[]=new Trie();
w=p->ch[];
build(w,id);
for(j=i+;j<l;++j){
if(!w->ch[begin[id][j]-''])
w->ch[begin[id][j]-'']=new Trie();
w=w->ch[begin[id][j]-''];
build(w,id);
}
w->mem.push_back(id);
if(!p->ch[])
p->ch[]=new Trie();
w=p->ch[];
build(w,id);
for(j=i+;j<l;++j){
if(!w->ch[begin[id][j]-''])
w->ch[begin[id][j]-'']=new Trie();
w=w->ch[begin[id][j]-''];
build(w,id);
}
w->mem.push_back(id);
return;
}
if(!p->ch[begin[id][i]-''])
p->ch[begin[id][i]-'']=new Trie();
p=p->ch[begin[id][i]-''];
build(p,id);
}
p->mem.push_back(id);
}
inline bool comp(int x,int y){
return len[x]<len[y];
}
inline void Init(){
root=new Trie();
scanf("%d",&n);
register int i,j;
for(i=;i<=n;++i){
pos[i]=-;
begin[i]=s+m;
scanf("%s",s+m);
len[i]=strlen(s+m);
m+=len[i];
temp[i]=i;
for(j=;j<len[i];++j)
if(begin[i][j]=='?'){
pos[i]=j;
break;
}
}
std::sort(temp+,temp+(n+),comp);
for(i=;i<=n;++i){
insert(temp[i]);
}
}
inline bool check(){
register int i;
for(i=;i<=(n<<);++i)
if(!dfn[i])
Tarjan(i);
for(i=;i<=n;++i)
if(belong[choose(i,)]==belong[choose(i,)])
return false;
return true;
}
int main(){
//freopen("rio.in","r",stdin);
Init();
puts(check()?"YES":"NO");
return ;
}

88分暴力

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register
const int N=;
struct V{int to,next;}c[N<<];
int head[N*],t;
inline void add(int x,int y){
c[++t].to=y,c[t].next=head[x],head[x]=t;
}
char s[N];
int n,cnt;
int dfn[N*],low[N*],belong[N*],stack[N*],top,num,Ti;
bool in[N*];
inline void Tarjan(int x){
dfn[x]=low[x]=++Ti;
stack[++top]=x;
in[x]=true;
R int i;
for(i=head[x];i;i=c[i].next)
if(!dfn[c[i].to]){
Tarjan(c[i].to);
low[x]=std::min(low[x],low[c[i].to]);
}else if(in[c[i].to])
low[x]=std::min(low[x],dfn[c[i].to]);
if(low[x]==dfn[x]){
++num;
do{
i=stack[top--];
in[i]=false;
belong[i]=num;
}while(i!=x);
}
}
#define H(a,b) (((a)<<1)-(b))
struct Trie{
Trie *ch[];
std::vector<int> mem;
Trie(){ch[]=ch[]=NULL,mem.clear();}
inline void* operator new(size_t);
}*root,*C,*mempool;
inline void* Trie::operator new(size_t){
if(C==mempool){
C=new Trie[(<<)+];
mempool=C+(<<)+;
}
return C++;
}
inline void dfs(Trie *p,int fa){
if(!p)return;
R int i,j,x,last=fa,size=p->mem.size();
for(i=;i<size;++i){
x=p->mem[i];
++cnt;
if(x>)j=;
else x=-x,j=;
add(H(x,j),H(cnt,));
add(H(cnt,),H(x,j^));
add(H(x,j),H(last,));
add(H(last,),H(x,j^));
add(H(cnt,),H(last,));
add(H(last,),H(cnt,));
last=cnt;
}
++cnt;
if(last){
add(H(cnt,),H(last,));
add(H(last,),H(cnt,));
}
last=cnt;
dfs(p->ch[],last);
dfs(p->ch[],last);
}
inline void insert(int id){
scanf("%s",s);
R Trie *p=root,*w;
R int i,j,l=strlen(s);
for(i=;i<l;++i)s[i]-='';
for(i=;i<l;++i){
if(s[i]>){
w=(!p->ch[])?p->ch[]=new Trie():p->ch[];
for(j=i+;j<l;++j)
w=(!w->ch[s[j]])?w->ch[s[j]]=new Trie():w->ch[s[j]];
w->mem.push_back(-id);
w=(!p->ch[])?p->ch[]=new Trie():p->ch[];
for(j=i+;j<l;++j)
w=(!w->ch[s[j]])?w->ch[s[j]]=new Trie():w->ch[s[j]];
w->mem.push_back(id);
return;
}
p=(!p->ch[s[i]])?p->ch[s[i]]=new Trie():p->ch[s[i]];
}
add(H(id,),H(id,));
p->mem.push_back(id);
}
inline bool check(){
R int i;
for(i=;i<=(cnt<<);++i)
if(!dfn[i])Tarjan(i);
for(i=;i<=cnt;++i)
if(belong[H(i,)]==belong[H(i,)])
return false;
return true;
}
int main(){
root=new Trie();
scanf("%d",&n),cnt=n;
R int i;
for(i=;i<=n;++i)insert(i);
dfs(root,);
puts(check()?"YES":"NO");
return ;
}

100分正解

LOJ #6036.「雅礼集训 2017 Day4」编码 Trie树上2-sat的更多相关文章

  1. Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat

    题目传送门 唯一的传送门 题目大意 给定$n$个串,每个串只包含 ' .问是否可能任意两个不同的串不满足一个是另一个的前缀. 2-sat的是显然的. 枚举每个通配符填0还是1,然后插入Trie树. 对 ...

  2. loj 6037 「雅礼集训 2017 Day4」猜数列 - 动态规划

    题目传送门 传送门 题目大意 有一个位置数列,给定$n$条线索,每条线索从某一个位置开始,一直向左或者向右走,每遇到一个还没有在线索中出现的数就将它加入线索,问最小的可能的数列长度. 依次从左到右考虑 ...

  3. LOJ #6037.「雅礼集训 2017 Day4」猜数列 状压dp

    这个题的搜索可以打到48分…… #include <cstdio> #include <cstring> #include <algorithm> ; bool m ...

  4. 2018.10.27 loj#6035. 「雅礼集训 2017 Day4」洗衣服(贪心+堆)

    传送门 显然的贪心题啊...考试没调出来10pts滚了妙的一啊 直接分别用堆贪心出洗完第iii件衣服需要的最少时间和晾完第iii件衣服需要的最少时间. 我们设第一个算出来的数组是aaa,第二个是bbb ...

  5. LOJ#6035. 「雅礼集训 2017 Day4」洗衣服

    传送门 先处理出每一件衣服最早什么时候洗完,堆+贪心即可 然后同样处理出每件衣服最早什么时候烘干 然后倒序相加取最大值 # include <bits/stdc++.h> using na ...

  6. LOJ #6035.「雅礼集训 2017 Day4」洗衣服 贪心

    这道题的贪心好迷啊~我们对于两个过程进行单独贪心,然后再翻转一个,把这两个拼起来.先说一下单独贪心,单独贪心的话就是用一个堆,每次取出最小的,并且把这个最小的加上他单次的,再放进去.这样,我们得到的结 ...

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

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

  8. [LOJ 6031]「雅礼集训 2017 Day1」字符串

    [LOJ 6031] 「雅礼集训 2017 Day1」字符串 题意 给定一个长度为 \(n\) 的字符串 \(s\), \(m\) 对 \((l_i,r_i)\), 回答 \(q\) 个询问. 每个询 ...

  9. [LOJ 6030]「雅礼集训 2017 Day1」矩阵

    [LOJ 6030] 「雅礼集训 2017 Day1」矩阵 题意 给定一个 \(n\times n\) 的 01 矩阵, 每次操作可以将一行转置后赋值给某一列, 问最少几次操作能让矩阵全为 1. 无解 ...

随机推荐

  1. Java基础知识:Java实现Map集合二级联动4

    comboBox.setModel(new DefaultComboBoxModel(getProvince())); // 添加省份信息 final JLabel label = new JLabe ...

  2. leetcode12_C++整数转罗马数字

    小弟不才,有错误或者更好解,求留言. 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, ...

  3. Python 并行分布式框架:Celery 超详细介绍

    本博客摘自:http://blog.csdn.net/liuxiaochen123/article/details/47981111 先来一张图,这是在网上最多的一张Celery的图了,确实描述的非常 ...

  4. VR产业链全景图

  5. Scrum立会报告+燃尽图(06)选题

    此作业要求参见:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2195] 一.小组介绍 组长:王一可 组员:范靖旋,王硕,赵佳璐,范洪达 ...

  6. 20172332『Java程序设计』课程结对编程练习_四则运算第二周阶段总结

    20172313『Java程序设计』课程结对编程练习_四则运算第二周阶段总结 小组成员 20172326康皓越 20172313余坤澎 20172332于欣月 小组编程照片 设计思路 设计一个生成符号 ...

  7. maven项目org.springframework.web.context.ContextLoaderListener的异常和tomcat zipexception的异常

    使用到spring的maven web项目,在运行servers时,报错找不到org.springframework.web.context.ContextLoaderListener,web.xml ...

  8. Java中static关键字的作用和用法详细介绍

    static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何 ...

  9. 【第三周】【】cppunit!

    coding.net地址:https://coding.net/u/Boxer_ ssh:git@git.coding.net:Boxer_/homework.git https://coding.n ...

  10. POI操作Excel异常Cannot get a text value from a numeric cell

    控制台抛出异常:java.lang.IllegalStateException: Cannot get a text value from a numeric cell 在java中用POI解析exc ...