YZOJ P3195 [NOI2017]游戏
时间限制:1000MS 内存限制:524288KB
难度: \(6.4\)
-
题目描述
小 L 计划进行 \(n\) 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。
小 L 的赛车有三辆,分别用大写字母 \(A\)、\(B\)、\(C\) 表示。地图一共有四种,分别用小写字母 \(x\)、\(a\)、\(b\)、\(c\) 表示。其中,赛车 \(A\) 不适合在地图 \(a\) 上使用,赛车 \(B\) 不适合在地图 \(b\) 上使用,赛车 \(C\) 不适合在地图 \(c\) 上使用,而地图 \(x\) 则适合所有赛车参加。适合所有赛车参加的地图并不多见,最多只会有 \(d\) 张。
\(n\) 场游戏的地图可以用一个小写字母组成的字符串描述。例如:\(S=\underline{\mathrm{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\)”(不含双引号)。
若有解,则包含一个长度为 \(n\) 的仅包含大写字母 \(A\)、\(B\)、\(C\) 的字符串,表示小 L 在这 \(n\) 场游戏中如何安排赛车的使用。如果存在多组解,输出其中任意一组即可。
-
样例输入
1 2 3 4 |
3 1 xcc 1 1 A 2 B |
-
样例输出
1 |
ABA |
-
样例解释
小 L 计划进行 \(3\) 场游戏,其中第 \(1\) 场的地图类型是 \(x\),适合所有赛车,第 \(2\) 场和第 \(3\) 场的地图是 \(c\),不适合赛车 \(C\) 。
小 L 希望:若第 \(1\) 场游戏使用赛车 \(A\),则第 \(2\) 场游戏使用赛车 \(B\) 。
那么为这 \(3\) 场游戏分别安排赛车 \(A\)、\(B\)、\(A\) 可以满足所有条件。
若依次为 \(3\) 场游戏安排赛车为 \(BBB\) 或 \(BAA\) 时,也可以满足所有条件,也被视为正确答案。但依次安排赛车为 \(AAB\) 或 \(ABC\) 时,因为不能满足所有条件,所以不被视为正确答案。
-
数据规模与约定
\(n \leq 50000, m \leq 100000, d \leq 8\)
注意到 \(d \leq 8\),所以可以 \(O(2^d)\)(去掉重复状态)枚举其字符,然后就是一个裸的 2-SAT 。
每场游戏两个点表示第一个/第二个可以取的字符,然后按照套路连边。
输出方案数的时候可以直接按照找出强连通块的编号大小判断取不取,因为 Tarjan 缩出来的连通块编号就是按照拓扑逆序的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #define _min(_a_,_b_) ((_a_)<(_b_)?(_a_):(_b_)) int gcnt,ghead[105050],gnext[205050],gnode[205050]; inline void insertLine(register int s,register int t) { gnext[++gcnt]=ghead[s],ghead[s]=gcnt,gnode[gcnt]=t; //printf("%d -> %d\n",s,t); } char s[50505]; int N; inline int ReverseIndex(register int x) { return (x > N ? x-N : x+N); } #define RoundNext(_x) (((_x)+1)%3) inline int GetIndex(register int x,register char c) { if(RoundNext(s[x]-'a') == c-'A') return x; else return x+N; } int cnt,dfn[105050],low[105050],belong[105050],bcnt; bool ins[105050]; int stk[105050],top; void Tarjan(register int o) { dfn[o]=low[o]=++cnt; ins[o]=true,stk[++top]=o; for(register int j=ghead[o],t;j;j=gnext[j]) if(!dfn[t=gnode[j]]) Tarjan(t),low[o]=_min(low[o],low[t]); else if(ins[t]) low[o]=_min(low[o],dfn[t]); if(dfn[o] == low[o]) { register int bo=++bcnt; ins[o]=false,belong[o]=bo; while(top && stk[top]!=o) ins[stk[top]]=false,belong[stk[top]]=bo,stk[top--]=0; top--; } } int M,qi[105050],qj[105050]; char qhi[105050],qhj[105050]; inline void Solve() { gcnt=0,memset(ghead,0,sizeof(ghead)); for(register int i=1,u,v;i<=M;i++) // turn qi[i] can't select qhi[i] if(s[qi[i]]-'a' == qhi[i]-'A') continue; // turn qj[i] can't select qhj[i] and above else if(s[qj[i]]-'a' == qhj[i]-'A') u=GetIndex(qi[i],qhi[i]),insertLine(u,ReverseIndex(u)); // standard 2-SAT else { u=GetIndex(qi[i],qhi[i]),v=GetIndex(qj[i],qhj[i]); insertLine(u,v); insertLine(ReverseIndex(v),ReverseIndex(u)); } cnt=0,memset(dfn,0,sizeof(dfn)),memset(low,0,sizeof(low)); bcnt=0,memset(belong,0,sizeof(belong)),top=0; for(register int i=1;i<=(N<<1);i++) if(!dfn[i]) Tarjan(i); for(register int i=1;i<=N;i++) if(belong[i] == belong[ReverseIndex(i)]) return; for(register int i=1;i<=N;i++) if(belong[i] < belong[ReverseIndex(i)]) putchar(RoundNext(s[i]-'a')+'A'); else putchar(RoundNext(RoundNext(s[i]-'a'))+'A'); putchar('\n'); exit(0); } int xpos[10]; int main() { int D;scanf("%d%d",&N,&D); scanf("%s",&s[1]); register int lx=0; for(register int i=1;i<=N;i++) if(s[i] == 'x') xpos[++lx]=i; scanf("%d",&M); for(register int i=1;i<=M;i++) scanf("%d %c%d %c",&qi[i],&qhi[i],&qj[i],&qhj[i]); if(!D) Solve(); else for(register int bin=0;bin<(1<<(D-1));bin++) { //printf("state %d\n",bin); register int tbin=bin; for(register int i=1;i<=D;i++,tbin>>=1) s[xpos[i]]=((tbin&1) ? 'b' : 'a'); Solve(); } printf("%d\n",-1); return 0; } |