题目传送门

  唯一的传送门

题目大意

  给定$n$个串,每个串只包含 '','','?' ,其中 '?' 至多在每个串中出现1次,它可以被替换为 '' 或 '' 。问是否可能任意两个不同的串不满足一个是另一个的前缀。

  2-sat的是显然的。

  枚举每个通配符填0还是1,然后插入Trie树。

  对于Trie的每个点在2-sat中建点。

  如果其中一个点被选择,那么它祖先和所有后继的结束点都不能选。(然后逆否命题连边)

  对于一个包含通配符的串,通配符替换为0以及通配符替换为1的否命题等价,同样,通配符替换为1以及通配符替换为0的否命题等价(连双向边)。

  对于一个不包含通配符的串,直接它到的节点的从否命题节点连一条到它的有向边。

  于是我们得到边数平方的优秀做法。

  考虑前缀和优化,新建一个虚点表示Trie树上,它的祖先的命题都是假。但是这样还有点问题,还要建一个点表示Trie上,它的所有后继的命题都是假。

  建图比较繁杂,见下图:

  然后再说一下处理多个串在Trie树上共点。

  于是便有了点数$12n$的优秀做法。再由于代码常数巨大无比,成功Loj最慢榜榜首,sad。。。(一定要去学习一下榜首同学点数$4n$的优质做法)

Code

 /**
* loj.ac
* Problem#6036
* Accepted
* Time: 4346ms
* Memory: 469852k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = 5e5 + ; typedef class TrieNode {
public:
int id;
TrieNode* ch[];
vector<int> vs;
}TrieNode; TrieNode pool[N << ];
TrieNode* top = pool; TrieNode* newnode() {
top->id = ;
top->ch[] = top->ch[] = NULL;
return top++;
} typedef class Trie {
public:
TrieNode* rt; Trie():rt(newnode()) { } int insert(char* str, int id) {
TrieNode* p = rt;
for (int i = , c; str[i]; i++) {
c = str[i] - '';
if (!p->ch[c])
p->ch[c] = newnode();
p = p->ch[c];
}
if (!p->id)
p->id = id;
else if ((!p->vs.size() || p->vs[p->vs.size() - ] != id - ) && p->id != id - )
p->vs.push_back(id);
return p->id;
}
}Trie; int n, n2;
char buf1[N], buf2[N];
vector<int> g[N * ];
// 1 ~ 2 * n2 : Is the node seclected?
// 2 * n2 + 1 ~ 4 * n2: Aren't nodes above seclected?
// 4 * n2 + 1 ~ 6 * n2: Aren't nodes below seclected?
Trie tr; inline void init() {
scanf("%d", &n);
n2 = n << ;
for (int i = , len, p1, p2; i <= n; i++) {
scanf("%s", buf1);
len = strlen(buf1);
memcpy(buf2, buf1, len + );
for (int j = ; j < len; j++)
if (buf1[j] == '?')
buf1[j] = '';
for (int j = ; j < len; j++)
if (buf2[j] == '?')
buf2[j] = '';
p1 = tr.insert(buf1, (i << ) - );
p2 = tr.insert(buf2, i << );
if (p1 == p2) {
g[(i << ) - + n2].push_back((i << ) - );
} else {
p1 = ((i << ) - ), p2 = (i << );
g[p1].push_back(p2 + n2);
g[p2 + n2].push_back(p1);
g[p2].push_back(p1 + n2);
g[p1 + n2].push_back(p2);
}
}
} #define virt(_x) (_x + n2)
#define upre(_x) (_x + n2 * 2)
#define upvi(_x) (_x + n2 * 3)
#define dore(_x) (_x + n2 * 4)
#define dovi(_x) (_x + n2 * 5) void dfs(TrieNode* p, int last) {
if (!p) return;
if (p->vs.size()) {
vector<int> &ve = p->vs;
for (int i = ; i < (signed) ve.size(); i++) {
TrieNode* q = newnode();
q->id = ve[i];
q->ch[] = p->ch[], q->ch[] = p->ch[];
p->ch[] = NULL, p->ch[] = q;
}
ve.clear();
}
int id = p->id;
if (id) {
g[id].push_back(upvi(id));
g[id].push_back(dovi(id));
g[upre(id)].push_back(virt(id));
g[dore(id)].push_back(virt(id));
if (last) {
g[id].push_back(upre(last));
g[upvi(last)].push_back(virt(id));
g[last].push_back(dore(id));
g[dovi(id)].push_back(virt(last)); g[upre(id)].push_back(upre(last));
g[upvi(last)].push_back(upvi(id));
g[dore(last)].push_back(dore(id));
g[dovi(id)].push_back(dovi(last));
}
}
int nid = ((id) ? (id) : (last));
dfs(p->ch[], nid);
dfs(p->ch[], nid);
} int dfs_clock = ;
stack<int> st;
boolean vis[N * ], ins[N * ];
int dfn[N * ], low[N * ];
void tarjan(int p) {
vis[p] = true, ins[p] = true;
dfn[p] = low[p] = ++dfs_clock;
st.push(p);
for (int i = ; i < (signed) g[p].size(); i++) {
int e = g[p][i];
if (!vis[e]) {
tarjan(e);
low[p] = min(low[p], low[e]);
} else if (ins[e])
low[p] = min(low[p], dfn[e]);
} if (dfn[p] == low[p]) {
int cur;
do {
cur = st.top();
st.pop();
low[cur] = low[p];
ins[cur] = false;
} while (cur != p);
}
} void putans(const char* str) {
puts(str);
exit();
} inline void solve() {
dfs(tr.rt, );
for (int i = ; i <= n2 * ; i++)
if (!vis[i])
tarjan(i);
for (int i = ; i <= n2; i++) {
if (low[i] == low[virt(i)])
putans("NO");
if (low[upre(i)] == low[upvi(i)])
putans("NO");
if (low[dore(i)] == low[dovi(i)])
putans("NO");
}
putans("YES");
} int main() {
init();
solve();
return ;
}

Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat的更多相关文章

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

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

  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. kaggle竞赛-保险转化-homesite

    时间格式的转化 查看数据类型 查看DataFrame的详细信息 填充缺失值 category 数据类型转化 模型参数设定 结论 该项目是针对kaggle中的homesite进行的算法预测,使用xgbo ...

  2. unicode 与 utf-8 编码概念及区别

    unicode 是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案.每个字符都对应一个编号,编号的范围是0-0x10FFFF来.Unicode 是为了解决传统的字符编码方案的局限而产生的,它为 ...

  3. MySQL建表、插入语句等

    不定时更新MySQL的一些基础语句以及出现过的问题 5.10 建表语句 CREATE TABLE `policy_landvalue` ( `id` ) NOT NULL AUTO_INCREMENT ...

  4. Python学习之旅(二十四)

    Python基础知识(23):进程和线程(Ⅱ) 一.threadlocal 在多线程环境下,每个线程都有自己的数据 一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响 ...

  5. ASP.NET Core 集成测试中通过 Serilog 向控制台输出日志

    日志是程序员的雷达,不仅在生产环境中需要,在集成测试环境中也需要,可以在持续集成失败后帮助定位问题.与生产环境不同,在集成测试环境中使用控制台输出日志更方便,这样可以通过持续集成 runner 执行 ...

  6. Codeforces 1136C - Nastya Is Transposing Matrices

    题目链接:https://codeforces.com/problemset/problem/1136/C 题意: 给出 $n \times m$ 的矩阵 $A,B$,你可以对其中任意某个 $k \t ...

  7. day20:序列化模块,模块的导入

    1,什么是序列化--将原本的字典,列表等内容转换成一个字符串的过程就叫做序列化,字符串是有顺序的,序列化转向一个字符串的过程,我们平时说的序列,指的就是字符串. 2,为何要序列化?本来字符串是可以强转 ...

  8. 架构4(lvs lb集群解决方案二 lvs+keepalived)

    keepalived 1.实现调度器的HA 2.对realserver做健康检测 3.动态维护ipvs路由表

  9. Bootstrap modal模态框关闭时,combobox input下拉框仍然保留在页面上

    问题描述: 当点击模态框的关闭按钮时,下拉框中的内容没有消失,而是移动到了页面左上角 分析:这个问题的定位在于是用的哪种模态框,bootstrap和easyui都可以实现模态框,但是两个方法实现的模态 ...

  10. Java-idea-安装配置优化等

    1.属性配置 使用版本,winzip解压版,开发工具安装目录下idea.properties文件,自定义配置路径 # idea.config.path=${user.home}/.IntelliJId ...