@loj - 2305@ 「NOI2017」游戏


@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, hi, j, hj) 来描述,表示若在第 i 场使用型号为 hi 的车子,则第 j 场游戏要使用型号为 hj 的车子。

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

输入格式
输入第一行包含两个非负整数 n, d。输入第二行为一个字符串 S。
n, d, S 的含义见题目描述,其中 S 包含 n 个字符,且其中恰好 d 个为小写字母 x。
输入第三行为一个正整数 m,表示有 m 条用车规则。
接下来 m 行,每行包含一个四元组 i, hi, j, hj,其中 i, j 为整数,hi, hj 为字符 A、B 或 C,含义见题目描述。

输出格式
输出一行。
若无解输出 -1。

样例
样例输入
3 1
xcc
1
1 A 2 B
样例输出
ABA

数据范围与提示
n <= 5*10^4, d <= 8, m <= 10^5。

@solution@

“选了某个东西就必须要选另一个东西” 这样的二元依赖关系,不难想到使用 2-sat。

假如不考虑那 d 个能取 A, B, C 的变量,剩下的变量恰好从两个状态中选(A+B 或 B+C 或 C+A)。
我们对于这些二元变量就可以直接利用 2-sat 建图。注意要判断 i 是否能取 hi,j 是否能取 hj。
2-sat 判断是否合法,合法时求任意方案都是基本功了,此处不再提。

那 d 个变量怎么办呢?注意到 d 很小,我们可以直接指数级暴力枚举。
如果枚举这 d 个变量取 A, B, C 中的哪一个,复杂度为 O(3^d*m),不能通过所有数据。
这个枚举太不优雅了,我们尝试枚举过后把这 d 个变量加入 2-sat 系统中。

枚举这 d 个变量是强制为 A,或者是 B 与 C 中的某一个。后一种情况直接在 2-sat 中建边即可。
那么就可以 O(2^d*m) AC 这道题了。

@accepted code@

#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 2*50000;
const int MAXM = 2*150000;
struct Graph{
	struct edge{
		int to; edge *nxt;
	}edges[MAXM + 5], *adj[MAXN + 5], *ecnt;
	void addedge(int u, int v) {
		edge *p = (++ecnt);
		p->to = v, p->nxt = adj[u], adj[u] = p;
	}
	void clear(int n) {
		ecnt = edges;
		for(int i=0;i<n;i++)
			adj[i] = NULL;
	}
}G;
int dfn[MAXN + 5], low[MAXN + 5], dcnt;
int stk[MAXN + 5], tp, id[MAXN + 5], tot;
void dfs(int x) {
	dfn[x] = low[x] = (++dcnt), stk[++tp] = x;
	for(Graph::edge *p=G.adj[x];p;p=p->nxt) {
		if( !dfn[p->to] )
			dfs(p->to), low[x] = min(low[x], low[p->to]);
		else if( !id[p->to] )
			low[x] = min(low[x], dfn[p->to]);
	}
	if( low[x] >= dfn[x] ) {
		tot++;
		do {
			id[stk[tp]] = tot;
		}while( stk[tp--] != x );
	}
}
int n, m, d;
bool solve() {
	for(int i=0;i<(n<<1);i++)
		dfn[i] = low[i] = id[i] = 0;
	dcnt = tot = tp = 0;
	for(int i=0;i<(n<<1);i++)
		if( !dfn[i] ) dfs(i);
	for(int i=0;i<n;i++)
		if( id[i<<1] == id[i<<1|1] )
			return false;
	return true;
}
int tag[MAXN + 5];
int c[3][MAXN + 5];
vector<int>vec[MAXN + 5];
void print() {
	for(int i=0;i<(n<<1);i++)
		vec[id[i]].push_back(i);
	for(int i=1;i<=tot;i++) tag[i] = 1;
	for(int i=1;i<=tot;i++) {
		if( tag[i] == 1 ) {
			for(int j=0;j<vec[i].size();j++) {
				for(Graph::edge *p=G.adj[vec[i][j]];p;p=p->nxt)
					if( tag[id[p->to]] == 0 ) {
						tag[i] = 0;
						break;
					}
				if( tag[i] == 0 ) break;
			}
		}
		if( tag[i] == 1 ) {
			for(int j=0;j<vec[i].size();j++)
				tag[id[vec[i][j]^1]] = 0;
		}
	}
	for(int i=0;i<n;i++)
		for(int j=0;j<3;j++)
			if( c[j][i] != -1 && tag[id[i<<1|c[j][i]]] )
				putchar(j + 'A');
}
int xp[10], cnt;
int u[MAXM + 5], v[MAXM + 5], cu[MAXM + 5], cv[MAXM + 5];
char S[MAXN + 5], op[5];
int main() {
	scanf("%d%d%s", &n, &d, S);
	for(int i=0;i<n;i++)
		if( S[i] == 'x' ) xp[cnt++] = i;
		else {
			int ch = S[i] - 'a';
			c[ch][i] = -1, c[(ch+1)%3][i] = 0, c[(ch+2)%3][i] = 1;
		}
	scanf("%d", &m);
	for(int i=0;i<m;i++) {
		scanf("%d%s", &u[i], op), cu[i] = op[0] - 'A', u[i]--;
		scanf("%d%s", &v[i], op), cv[i] = op[0] - 'A', v[i]--;
	}
	int t = (1<<d);
	for(int s=0;s<t;s++) {
		G.clear(n << 1);
		for(int i=0;i<d;i++) {
			if( !((s >> i) & 1) )
				c[0][xp[i]] = -1, c[1][xp[i]] = 0, c[2][xp[i]] = 1;
			else {
				c[0][xp[i]] = 0, c[1][xp[i]] = c[2][xp[i]] = -1;
				G.addedge(xp[i]<<1|1, xp[i]<<1);
			}
		}
		for(int i=0;i<m;i++) {
			if( c[cu[i]][u[i]] != -1 ) {
				int p = c[cu[i]][u[i]];
				if( c[cv[i]][v[i]] == -1 )
					G.addedge(u[i]<<1|p, u[i]<<1|(!p));
				else {
					int q = c[cv[i]][v[i]];
					G.addedge(u[i]<<1|p, v[i]<<1|q);
					G.addedge(v[i]<<1|(!q), u[i]<<1|(!p));
				}
			}
		}
		if( solve() ) {
			print();
			return 0;
		}
	}
	puts("-1");
}

@detail@

复习 2-sat 中.jpg

posted @ 2019-11-13 22:21  Tiw_Air_OAO  阅读(162)  评论(0编辑  收藏  举报