Description

题库链接

小 L 计划进行 \(n\) 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。

小 L 的赛车有三辆,分别用大写字母 A、B、C 表示。地图一共有四种,分别用小写字母 x、a、b、c 表示。其中,赛车 A 不适合在地图 a 上使用,赛车 B 不适合在地图 b 上使用,赛车 C 不适合在地图 c 上使用,而地图 x 则适合所有赛车参加。适合所有赛车参加的地图并不多见,最多只会有 d 张。

\(n\) 场游戏的地图可以用一个小写字母组成的字符串描述。例如: S=xaabxcbc 表示小 L 计划进行 \(8\) 场游戏,其中第 \(1\) 场和第 \(5\) 场的地图类型是 x ,适合所有赛车,第 \(2\) 场和第 \(3\) 场的地图是 a ,不适合赛车 A ,第 \(4\) 场和第 \(7\) 场的地图是 b ,不适合赛车 B ,第 \(6\) 场和第 \(8\) 场的地图是 c ,不适合赛车 C 。

小 L 对游戏有一些特殊的要求,这些要求可以用四元组 \((i, h_i, j, h_j)\) 来描述,表示若在第 \(i\) 场使用型号为 \(h_i\) 的车子,则第 \(j\) 场游戏要使用型号为 \(h_j\) 的车子。

你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。如果无解,输出 -1(不含双引号)。

\(1\leq n\leq 50000,d\leq 8,1\leq m\leq 100000\)

Solution

容易发现,对于除 x 以外的位置,只能选择两个中的一个,可以建立 \(\text{2-SAT}\) 模型。剩下的 x 的位置,因为数量少,可以枚举。不过只要枚举这一位置是 a 或是 b ,因为 c 的情况已经被前两种情况涵盖了。

对于边的建立,对于四元组 \((i, h_i, j, h_j)\) ,记第 \(i\) 个位置上的字符为 \(S_i\) 。

  • 若 \(h_i=S_i\) ,直接忽略;
  • 若 \(h_j=S_j\) ,建一条 \(i\rightarrow i'\) 的边,表示强制选择 \(S_i\) 对应的另一种字符;
  • 其余情况,建边 \(i\rightarrow j\) , \(j'\rightarrow i'\)

直接跑 \(\text{2-SAT}\) 即可,复杂度是 \(O\left(2^d\times(m+n)\right)\) 。

Code

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N = (50000+5)<<1, M = 100000+5; int n, d, m, lst[10], tot, a[M], b[M], h1[M], h2[M];
char ch[N], s[2];
struct tt {int to, next; } edge[M<<1];
int path[N], top;
vector<int> scc[N], to[N];
vector<int>::iterator it;
queue<int> Q;
int dfn[N], low[N], ins[N], id[N], in[N], num, times, S[N], tp, cs[N]; void add(int u, int v) {edge[++top] = (tt){v, path[u]}, path[u] = top; }
int idx(int i, int c) {
if (ch[i] != 'c') return i+n*(c == 'C');
return i+n*(c == 'B');
}
int inv(int x) {return x <= n ? x+n : x-n; }
void tarjan(int u) {
dfn[u] = low[u] = ++times; ins[u] = 1; S[++tp] = u;
for (int i = path[u], v; i; i = edge[i].next) {
v = edge[i].to;
if (!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
else if (ins[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
++num; int v = 0;
do {
v = S[tp--]; id[v] = num;
scc[num].pb(v); ins[v] = 0;
}while (v != u);
}
}
void solve() {
memset(path, top = 0, sizeof(path));
for (int i = 1; i <= m; i++) {
if (ch[a[i]] == h1[i]+32) continue;
else if (ch[b[i]] == h2[i]+32) add(idx(a[i], h1[i]), inv(idx(a[i], h1[i])));
else {
int x = idx(a[i], h1[i]), y = idx(b[i], h2[i]);
add(x, y), add(inv(y), inv(x));
}
}
for (int i = 1; i <= n*2; i++) scc[i].clear(); num = 0;
memset(dfn, times = 0, sizeof(dfn));
for (int i = 1; i <= n*2; i++) if (!dfn[i]) tarjan(i);
for (int i = 1; i <= n; i++) if (id[i] == id[i+n]) return;
for (int u = 1; u <= n*2; u++)
for (int i = path[u], v; i; i = edge[i].next)
if (id[u] != id[v = edge[i].to]) to[id[v]].pb(id[u]), ++in[id[u]];
for (int i = 1; i <= num; i++) if (in[i] == 0) Q.push(i);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
if (ins[u]) continue; cs[u] = 1;
for (it = scc[u].begin(); it != scc[u].end(); it++) ins[id[inv(*it)]] = 1;
for (it = to[u].begin(); it != to[u].end(); it++) if (!(--in[*it])) Q.push(*it);
}
for (int i = 1; i <= n; i++)
if (cs[id[i]]) putchar('A'+(ch[i] == 'a'));
else putchar('C'-(ch[i] == 'c'));
exit(0);
}
void dfs(int x) {
if (x > tot) {solve(); return; }
ch[lst[x]] = 'a'; dfs(x+1);
ch[lst[x]] = 'b'; dfs(x+1);
}
void work() {
scanf("%d%d%s", &n, &d, ch+1);
for (int i = 1; i <= n; i++) if (ch[i] == 'x') lst[++tot] = i;
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
scanf("%d%s", &a[i], s); h1[i] = s[0];
scanf("%d%s", &b[i], s); h2[i] = s[0];
}
dfs(1); puts("-1");
}
int main() {work(); return 0; }

[NOI 2017]游戏的更多相关文章

  1. NOI 2017滚粗退役记

    NOI 2017 游记 又到了OIer退役了的季节 Day -1 今天是报到日. 中午11点多的动车.动车上和dick32165401和runzhe2000谈笑风生.顺便用dick32165401的流 ...

  2. CTSC 2017 游戏[概率dp 线段树]

    小 R 和室友小 B 在寝室里玩游戏.他们一共玩了 $n$ 局游戏,每局游戏的结果要么是小 R 获胜,要么是小 B 获胜. 第 $1$ 局游戏小 R 获胜的概率是 $p_1$,小 B 获胜的概率是 $ ...

  3. NOI Online 游戏 树形dp 广义容斥/二项式反演

    LINK:游戏 还是过于弱鸡 没看出来是个二项式反演,虽然学过一遍 但印象不深刻. 二项式反演:有两种形式 一种是以恰好和至多的转换 一种是恰好和至少得转换. 设\(f_i\)表示至多的方案数 \(g ...

  4. NOI 2017 整数(线段树)

    题意 https://loj.ac/problem/2302 思路 拆分成每个二进制位的加减来考虑,维护那个整数的二进制位.不难发现,进位就是找右边第一个 \(0\) 的位置,并将其赋值为 \(1\) ...

  5. [NOI 2017]蔬菜

    Description 题库链接 小 N 是蔬菜仓库的管理员,负责设计蔬菜的销售方案. 在蔬菜仓库中,共存放有 \(n\) 种蔬菜,小 N 需要根据不同蔬菜的特性,综合考虑各方面因素,设计合理的销售方 ...

  6. [NOI 2017]整数

    Description 题库链接 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 \(x\) ,一开始为 \(0\) . 接下来有 \(n\) 个操作,每个操作都是以下两种类型中 ...

  7. [NOI 2017]蚯蚓排队

    Description 题库链接 蚯蚓幼儿园有 \(n\) 只蚯蚓.幼儿园园长神刀手为了管理方便,时常让这些蚯蚓们列队表演. 所有蚯蚓用从 \(1\) 到 \(n\) 的连续正整数编号.每只蚯蚓的长度 ...

  8. NOI 2017 Day1 题解

    被虐爆了... T1 整数 题目传送门 Description 有一个整数 \(x\),有 \(n\) 此操作,每次操作为以下两种情况: 给出 \(a,b\),将 \(x\) 加上 \(a\times ...

  9. (转)2-SAT小结

    2-sat小结 原文作者:老K 原文传送门 2-sat是什么 一类问题是这样的: (两个符号的意思 \(\lor \ or,\land \ and\)) 有n个布尔变量,现在对它们做出限制,比如\(a ...

随机推荐

  1. Spring 框架下 事务的配置(复杂)

    //db.properties配置  src下的文件 jdbc.jdbcUrl=jdbc:mysql:///day43jdbc.driverClass=com.mysql.jdbc.Driverjdb ...

  2. ORA-12514: TNS:监听程序当前无法识别连接描述符中请

    若Oracle出现“监听程序当前无法识别连接描述符中请求的服务”这个错误可以按照以下方法解决: 可以通过这个路径找到一个文本文件: oracle\product\10.2.0\db_1\NETWORK ...

  3. python 常用知识点

    1,字典get用法 如果key没有值,返回一个None >>> dic = {'k1':'v1','k2':'v2','k3':'v3'} >>> dic.get( ...

  4. 相对于父元素的fixed定位的实现

    问题描述 之前在项目中,遇到了一个场景,需要实现相对于父元素的fixed定位:在父元素内拖动滚动条时,"fixed"定位的元素不能滑动,在外层拖动滚动条时,父元素及父元素内的所有元 ...

  5. RQNOJ 2 开心的金明

    一道基础的01背包,要是不明白可以自己搜一下背包九讲,自己刚开始数组开小了,题目看串了行,找了半天,小错还是要格外注意的. #include <iostream> #include < ...

  6. SpringMVC 学习 十一 springMVC控制器向jsp或者别的控制器传递参数的四种方法

    以后的开发,大部分是发送ajax,因此这四种传递参数的方法,并不太常用.作为了解吧 第一种:使用原生 Servlet 在控制器的响应的方法中添加Servlet中的一些作用域:HttpRequestSe ...

  7. VUE 动态给对象增加属性,并触发视图更新。

    在开发过程中,我们时常会遇到这样一种情况:当vue的data里边声明或者已经赋值过的对象或者数组(数组里边的值是对象)时,向对象中添加新的属性,如果更新此属性的值,是不会更新视图的. 根据官方文档定义 ...

  8. 深入理解定位父级offsetParent及偏移大小offsetTop / offsetLeft / offsetHeight / offsetWidth

    深入理解定位父级offsetParent及偏移大小 [转载] 前面的话 偏移量(offset dimension)是javascript中的一个重要的概念.涉及到偏移量的主要是offsetLeft.o ...

  9. python_day1_变量

    一.变量 定义: 通俗来讲可变化的量称之为变量,专业的解释为:把程序运算的中间结果临时存到内存里,以备后面的代码继续调用,这几个名字的学名就叫做“变量” 用法: name = 'zzx' 其中name ...

  10. 《mysql必知必会》学习_第19章_20180809_欢

    第19章 插入数据 P132 insert into customers VALUES(NULL,'Pep E.Lapew','100 Main Street',,Los Angeles','CA', ...