发现,这仿佛在提示我们要暴力枚举代表的是什么,注意到和就可以覆盖到的所有情况,所以我们只要枚举是或即可,时间复杂度,我们把枚举出来的地图序列叫做
考虑这样编号,对应,对应,对应
但是这样太过愚蠢,我们知道是什么,所以一个位置不能放什么我们是知道的,不妨这样编号:
,不能放,那么只能放,
,不能放,那么只能放,
,不能放,那么只能放,
简单来说,就是按照字典序编号。
如图:

接下来分类讨论即可。
我们设代表的序列为,代表的序列为,
1.
这就是告诉我们不能选,否则选了就挂了,直接continue掉。
if (f1[i]==Map[a[i]]){//一旦选了就挂了
continue;
}
2.
这也是告诉我们不能选,但是我们可以选其他的,整理一下思路,发现不能选不能选,根据上面我们的特判,发现,所以只有一个字母能选。
如何建一个图,强制选剩下的那个字母,这里我们使用奇巧淫技,假设第一列选了第三列就必须选,现在我们知道第一列只能选,就连一条,这样你选了就必须选,造成矛盾,等于是强制选了

else if (f2[i]==Map[b[i]]){//也是选了就挂了,但是有一种可以的选择
//eg. a[i]=='B' Map[f1[i]]=='A' so 只能选'C'
int delta=GetDelta1(i);
AddEdge(a[i]+delta,a[i]+n-delta);
}
3.
这是最普通的情况,假设第一列选了第三列就必须选,按照的问题的套路,我们要寻找有依赖性关系的点对,显然,选了第一列的,就必须选第三列的,还有,选了第三列的,就必须选第一列的,否则会发生矛盾,于是他们两个点对连边:

int delta1=GetDelta1(i),delta2=GetDelta2(i);
AddEdge(a[i]+delta1,b[i]+delta2);
AddEdge(b[i]+n-delta2,a[i]+n-delta1);
代码写的比较丑陋,其中一些细节模拟一下就知道了。
#include <bits/stdc++.h>
#define MAXN 2000005
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^'0');
ch=getchar();
}
return x*f;
}
vector<int>G[MAXN];
inline void AddEdge(int u,int v){
G[u].push_back(v);
}
int dfn[MAXN],low[MAXN],cnt;
stack<int>stk;
int scc,col[MAXN];
void tarjan(int u){
dfn[u]=low[u]=++cnt;
stk.push(u);
for (register int i=0;i<G[u].size();++i){
int v=G[u][i];
if (!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
else if (!col[v]) low[u]=min(low[u],dfn[v]);
}
if (low[u]==dfn[u]){
++scc;
do{
col[u]=scc;
u=stk.top(),stk.pop();
}while (low[u]!=dfn[u]);
}
}
inline char GetPre(char ch){
if (ch=='A') return 'B';
if (ch=='B') return 'A';
if (ch=='C') return 'A';
}
inline char GetNex(char ch){
if (ch=='A') return 'C';
if (ch=='B') return 'C';
if (ch=='C') return 'B';
}
inline char gc(){
char ch=getchar();
while (!isalpha(ch)) ch=getchar();
if (ch>='a'&&ch<='z') return ch-'a'+'A';
else return ch;
}
char Map[MAXN],ans[MAXN];
int a[MAXN],b[MAXN];
char f1[MAXN],f2[MAXN];
int pos[MAXN];//存的是x的下标
int n,m,d;
inline void Init(){
while (stk.size()) stk.pop();
memset(col,0,sizeof(col));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
scc=cnt=0;
for (register int i=0;i<MAXN;++i){
G[i].clear();
}
}
inline void GetAns(){
bool flag=true;
for (register int i=1;i<=n*2;++i){
if (!dfn[i]) tarjan(i);
}
for (register int i=1;i<=n;++i){
if (col[i]==col[i+n]){
flag=false;
break;
}
if (col[i]<col[i+n]) ans[i-1]=GetPre(Map[i]);
else ans[i-1]=GetNex(Map[i]);
}
if (flag==true){
cout<<ans;
exit(0);
}
}
inline int GetDelta1(int pos){
//写成注释里这样可能方便理解
// if (Map[a[pos]]=='A'&&f1[pos]=='B') return 0;
// if (Map[a[pos]]=='A'&&f1[pos]=='C') return n;
// if (Map[a[pos]]=='B'&&f1[pos]=='A') return 0;
// if (Map[a[pos]]=='B'&&f1[pos]=='C') return n;
// if (Map[a[pos]]=='C'&&f1[pos]=='A') return 0;
// if (Map[a[pos]]=='C'&&f1[pos]=='B') return n;
return (f1[pos]=='A'||(f1[pos]=='B'&&Map[a[pos]]=='A'))?0:n;
}
inline int GetDelta2(int pos){
// if (Map[b[pos]]=='A'&&f2[pos]=='B') return 0;
// if (Map[b[pos]]=='A'&&f2[pos]=='C') return n;
// if (Map[b[pos]]=='B'&&f2[pos]=='A') return 0;
// if (Map[b[pos]]=='B'&&f2[pos]=='C') return n;
// if (Map[b[pos]]=='C'&&f2[pos]=='A') return 0;
// if (Map[b[pos]]=='C'&&f2[pos]=='B') return n;
return (f2[pos]=='A'||(f2[pos]=='B'&&Map[b[pos]]=='A'))?0:n;
}
int main(){
n=read(),d=read();
int c=0;
scanf("%s",Map+1);
for (register int i=1;i<=n;++i){
Map[i]-='a',Map[i]+='A';
if (Map[i]=='X') pos[++c]=i;
}
m=read();
for (register int i=1;i<=m;++i){
a[i]=read(),f1[i]=getchar(),b[i]=read(),f2[i]=getchar();
getchar();
}
for (register int v=0;v<(1<<d);++v){
Init();
for (register int i=1;i<=d;++i){
if (v&(1<<(i-1))) Map[pos[i]]='A';
else Map[pos[i]]='B';
}
for (register int i=1;i<=m;++i){
if (f1[i]==Map[a[i]]){//一旦选了就挂了
continue;
}
else if (f2[i]==Map[b[i]]){//也是选了就挂了,但是有一种可以的选择
//eg. a[i]=='A' Map[f1[i]]=='B' so 只能选'C'
int delta=GetDelta1(i);
AddEdge(a[i]+delta,a[i]+n-delta);
}
else {
int delta1=GetDelta1(i),delta2=GetDelta2(i);
AddEdge(a[i]+delta1,b[i]+delta2);
AddEdge(b[i]+n-delta2,a[i]+n-delta1);
}
}
GetAns();
}
puts("-1");
}