zoukankan      html  css  js  c++  java
  • [LOJ#2305]「NOI2017」游戏

    [LOJ#2305]「NOI2017」游戏

    试题描述

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

    小 L 的赛车有三辆,分别用大写字母 (A)(B)(C) 表示。地图一共有四种,分别用小写字母 (x)(a)(b)(c) 表示。

    其中,赛车 (A) 不适合在地图 (a) 上使用,赛车 (B) 不适合在地图 (b) 上使用,赛车 (C) 不适合在地图 (c) 上使用,而地图 (x) 则适合所有赛车参加。

    适合所有赛车参加的地图并不多见,最多只会有 (d) 张。

    (n) 场游戏的地图可以用一个小写字母组成的字符串描述。例如:(S = exttt{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

    输入

    输入第一行包含两个非负整数 (n), (d)

    输入第二行为一个字符串 (S)

    (n), (d), (S) 的含义见题目描述,其中 (S) 包含 (n) 个字符,且其中恰好 (d) 个为小写字母 (x)

    输入第三行为一个正整数 (m),表示有 (m) 条用车规则。

    接下来 (m) 行,每行包含一个四元组 (i,h_i,j,h_j),其中 (i,j) 为整数,(h_i,h_j) 为字符 (A)(B)(C),含义见题目描述。

    输出

    输出一行。

    若无解输出 -1

    输入示例

    3 1
    xcc
    1
    1 A 2 B
    

    输出示例

    ABA
    

    数据规模及约定

    题解

    枚举那 (d)(x) 的地图用 (A) 还是用 ({ B, C }),变成 2-SAT 模型。

    #include <bits/stdc++.h>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define maxm 200010
    
    char Map[maxn], Ans[maxn];
    int n, m, D, Did[maxn], CntP;
    struct Clause {
    	int a, ta, b, tb;
    	Clause() {}
    	Clause(int _1, int _2, int _3, int _4): a(_1), ta(_2), b(_3), tb(_4) {}
    } cs[maxm];
    bool NeverHappen(int a, int ta, int s) {
    	if(Map[a] == ta + 'a') return 1;
    	if(ta && Map[a] == 'x' && (s >> Did[a] & 1)) return 1;
    	if(!ta && Map[a] == 'x' && !(s >> Did[a] & 1)) return 1;
    	return 0;
    }
    
    struct Point {
    	int id;
    	Point(): id(0) {}
    	int p() { return id ? id : id = ++CntP; }
    } use[maxn][3];
    int sumTp[maxn];
    
    namespace G {
    	int m, head[maxn], nxt[maxm], to[maxm];
    	void clear() {
    		m = 0; memset(head, 0, sizeof(head));
    		return ;
    	}
    	void AddEdge(int a, int b) {
    		to[++m] = b; nxt[m] = head[a]; head[a] = m;
    		return ;
    	}
    	
    	int dfn[maxn], low[maxn], clo, scno[maxn], cnts, S[maxn], top;
    	void init() {
    		memset(dfn, 0, sizeof(dfn));
    		memset(low, 0, sizeof(low));
    		clo = 0;
    		memset(scno, 0, sizeof(scno));
    		cnts = 0;
    		return ;
    	}
    	void dfs(int u) {
    		dfn[u] = low[u] = ++clo;
    		S[++top] = u;
    		for(int e = head[u]; e; e = nxt[e]) {
    			if(scno[to[e]]) continue;
    			if(dfn[to[e]]) low[u] = min(low[u], dfn[to[e]]);
    			else dfs(to[e]), low[u] = min(low[u], low[to[e]]);
    		}
    		if(low[u] == dfn[u]) {
    			cnts++;
    			while(S[top] != u) scno[S[top--]] = cnts;
    			scno[S[top--]] = cnts;
    		}
    		return ;
    	}
    }
    
    int main() {
    	n = read(); D = read();
    	scanf("%s", Map + 1);
    	m = read();
    	rep(i, 1, m) {
    		int a = read(), b;
    		char cha[5], chb[5];
    		scanf("%s", cha);
    		b = read();
    		scanf("%s", chb);
    		cs[i] = Clause(a, cha[0] - 'A', b, chb[0] - 'A');
    	}
    	
    	int cD = 0;
    	rep(i, 1, n) if(Map[i] == 'x') Did[i] = cD++;
    	int all = (1 << D) - 1;
    	rep(s, 0, all) {
    		CntP = 0;
    		memset(use, 0, sizeof(use));
    		G::clear();
    		
    		rep(i, 1, n) if(Map[i] != 'x') {
    			if(Map[i] == 'a') use[i][1].p(), use[i][2].p(), sumTp[i] = 3;
    			if(Map[i] == 'b') use[i][0].p(), use[i][2].p(), sumTp[i] = 2;
    			if(Map[i] == 'c') use[i][0].p(), use[i][1].p(), sumTp[i] = 1;
    		}
    		else {
    			if(s >> Did[i] & 1) G::AddEdge(use[i][1].p(), use[i][0].p()), sumTp[i] = 1;
    			else use[i][1].p(), use[i][2].p(), sumTp[i] = 3;
    		}
    		
    		rep(i, 1, m) {
    			if(NeverHappen(cs[i].a, cs[i].ta, s)) continue;
    			if(NeverHappen(cs[i].b, cs[i].tb, s)) G::AddEdge(use[cs[i].a][cs[i].ta].p(), use[cs[i].a][sumTp[cs[i].a]-cs[i].ta].p());
    			else
    				G::AddEdge(use[cs[i].a][cs[i].ta].p(), use[cs[i].b][cs[i].tb].p()),
    				G::AddEdge(use[cs[i].b][sumTp[cs[i].b]-cs[i].tb].p(), use[cs[i].a][sumTp[cs[i].a]-cs[i].ta].p());
    		}
    		G::init();
    		rep(i, 1, CntP) if(!G::dfn[i]) G::dfs(i);
    		
    		bool ok = 1;
    		rep(i, 1, n) {
    			if(sumTp[i] == 3) {
    				if(G::scno[use[i][1].p()] == G::scno[use[i][2].p()]) { ok = 0; break; }
    				else Ans[i] = G::scno[use[i][1].p()] < G::scno[use[i][2].p()] ? 'B' : 'C';
    			}
    			if(sumTp[i] == 2) {
    				if(G::scno[use[i][0].p()] == G::scno[use[i][2].p()]) { ok = 0; break; }
    				else Ans[i] = G::scno[use[i][0].p()] < G::scno[use[i][2].p()] ? 'A' : 'C';
    			}
    			if(sumTp[i] == 1) {
    				if(G::scno[use[i][0].p()] == G::scno[use[i][1].p()]) { ok = 0; break; }
    				else Ans[i] = G::scno[use[i][0].p()] < G::scno[use[i][1].p()] ? 'A' : 'B';
    			}
    		}
    		if(ok) return Ans[n+1] = 0, puts(Ans + 1), 0;
    	}
    	puts("-1");
    	
    	return 0;
    }
    
  • 相关阅读:
    记一道乘法&加法线段树(模版题)
    2021CCPC网络赛(重赛)题解
    Codeforces Round #747 (Div. 2)题解
    F. Mattress Run 题解
    Codeforces Round #744 (Div. 3) G题题解
    AtCoder Beginner Contest 220部分题(G,H)题解
    Educational Codeforces Round 114 (Rated for Div. 2)题解
    Codeforces Global Round 16题解
    Educational Codeforces Round 113 (Rated for Div. 2)题解
    AtCoder Beginner Contest 182 F
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/9159751.html
Copyright © 2011-2022 走看看