洛谷P3825 [NOI2017] 游戏 题解
题目链接:P3825 [NOI2017] 游戏
题意:
小 L 计划进行 \(n\) 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。
小 L 的赛车有三辆,分别用大写字母 \(A\)、\(B\)、\(C\) 表示。地图一共有四种,分别用小写字母 \(x\)、\(a\)、\(b\)、\(c\) 表示。
其中,赛车 \(A\) 不适合在地图 \(a\) 上使用,赛车 \(B\) 不适合在地图 \(b\) 上使用,赛车 \(C\) 不适合在地图 \(c\) 上使用,而地图 \(x\) 则适合所有赛车参加。
适合所有赛车参加的地图并不多见,最多只会有 \(d\) 张。
\(n\) 场游戏的地图可以用一个小写字母组成的字符串描述。例如:\(S=\texttt{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
。
什么恶心卡常题,心态要崩了。
这篇题解在uoj是过不了Extra Test 12
的,但是洛谷可以过hack数据。
显然 \(\mathtt{2-SAT}\) ,但是
x
的出现意味这道题还要加一个 \(\mathtt{3-SAT}\)
众所周知, \(\mathtt{k-SAT}\) 在 \(k>2\) 时被证明是NP完全的
因此只能暴力枚举所有 x
的选法
这里的暴力可以优化为枚举每个 x
地图为 a
地图还是 b
地图
这样为什么对呢?
因为 a
适合 BC
,b
适合
AC
,然后我们就把填 ABC
的三种情况都试过了
考虑没有 x
的部分怎么做
如果 \(i\) 的位置适合 \(h_i\) 赛车,但 \(j\) 不适合 \(h_j\) 赛车
则把 \(u_i\) 向 \(u_{i}^{\prime}\) 连有向边,表示如果选了 \(h_i\) 一定无解
如果 \(i\) 的位置适合 \(h_i\) 赛车,\(j\) 的位置适合 \(h_j\) 赛车
那就把 \(u_i\) 向 \(v_i\) 连有向边,\(v_{i}^{\prime}\) 向 \(u_{i}^{\prime}\) 连有向边,显然。
时间复杂度 \(O(2^d \times (n+m))\)
代码:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
#include <bitset>
using namespace std;
// #define int long long
// #define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
// #define gc() readchar()
#define gc() getchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e6+15)
char buf1[SIZ],*p1,*p2;
char readchar()
{
if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
char ch=gc();T x=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
k=x*f;
}
template<typename T>void write(T k)
{
if(k<0){k=-k;pc('-');}
static T stk[66];T top=0;
do{stk[top++]=k%10,k/=10;}while(k);
while(top){pc(stk[--top]+'0');}
}
void readc(char &ch)
{
char t=getchar();
while(!isupper(t)) t=gc();
ch=t;
}
}using namespace FastIO;
#define N ((int)(2e5+15))
bitset<N> vis,ins;
mt19937 rd(time(0));
int n,m,d,scnt,top,dfncnt,pos=1;
char s[N],col[N],a2[N],b2[N];
int head[N],id[N],a1[N],b1[N],stk[N],dfn[N],low[N],scc[N];
struct Edge{int u,v,next;} e[N];
int tran(int x,char c)
{
if(s[x]=='a') return c=='B'?x:x+n;
if(s[x]=='b'||s[x]=='c') return c=='A'?x:x+n;
if(c=='C') return x+n; return x;
}
int neg(int x){return x > n ? x-n : x+n;}
void addEdge(int u,int v)
{
e[++pos]={u,v,head[u]};
head[u]=pos;
}
bool Tarjan(int u)
{
dfn[u]=low[u]=++dfncnt;
ins[stk[++top]=u]=vis[u]=1;
for(int i=head[u]; i; i=e[i].next)
{
int v=e[i].v;
if(!vis[v])
{
if(!Tarjan(v)) return 0;
low[u]=min(low[u],low[v]);
}
else if(ins[v]) low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
int v; scc[u]=++scnt; ins[u]=0;
while(v=stk[top--],v!=u)
{
scc[v]=scnt,ins[v]=0;
if(scc[v]==scc[neg(v)]) return 0;
}
}
return 1;
}
bool solve()
{
scnt=dfncnt=top=0; pos=1; vis=ins=0;
for(int i=1; i<=(n<<1); i++) scc[i]=head[i]=dfn[i]=0;
for(int i=1; i<=m; i++)
{
if(s[a1[i]] != 'x' && s[b1[i]] != 'x')
{
if(a2[i] == s[a1[i]]-32) continue;
int u=tran(a1[i],a2[i]),v;
if(b2[i] == s[b1[i]]-32) {addEdge(u,neg(u)); continue;}
v=tran(b1[i],b2[i]); addEdge(u,v);
addEdge(neg(v),neg(u));
}else
{
char o = s[a1[i]], p = s[b1[i]];
int u,v, x=id[a1[i]], y=id[b1[i]];
if(o == 'x' && p == 'x')
{
if(a2[i] == col[x]) continue;
u=tran(a1[i],a2[i]);
if(b2[i] == col[y]) {addEdge(u,neg(u)); continue;}
v=tran(b1[i],b2[i]); addEdge(u,v);
addEdge(neg(v),neg(u));
}
else if(o == 'x' && p != 'x')
{
if(a2[i] == col[x]) continue;
u=tran(a1[i],a2[i]);
if(b2[i] == s[b1[i]]-32) {addEdge(u,neg(u)); continue;}
v=tran(b1[i],b2[i]); addEdge(u,v);
addEdge(neg(v),neg(u));
}
else
{
if(a2[i] == s[a1[i]]-32) continue;
u=tran(a1[i],a2[i]);
if(b2[i] == col[y]) {addEdge(u,neg(u)); continue;}
v=tran(b1[i],b2[i]); addEdge(u,v);
addEdge(neg(v),neg(u));
}
}
}
for(int i=1; i<=(n<<1); i++) if(!vis[i]&&!Tarjan(i)) return 0;
for(int i=1; i<=n; i++)
{
if(scc[i]<scc[i+n])
{
if(s[i]=='a') pc('B');
else if(s[i]=='b'||s[i]=='c') pc('A');
else if(col[id[i]]=='A') pc('B');
else pc('A');
}else
{
if(s[i]=='a'||s[i]=='b') pc('C');
else if(s[i]=='c') pc('B');
else if(col[id[i]]=='A') pc('C');
else pc('B');
}
}
puts("");
return 1;
}
signed main()
{
int st=clock();
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int _; read(n); read(_); scanf("%s",s+1); read(m);
for(int i=1; i<=n; i++) if(s[i]=='x') id[i]=++d;
for(int i=1; i<=m; i++) read(a1[i]),readc(a2[i]),read(b1[i]),readc(b2[i]);
for(int i=0; i<(1<<d); i++)
{
for(int j=0; j<d; j++) col[j+1]=((i>>j)&1)?'B':'A';
if(solve()) return 0;
}
puts("-1");
// printf("times used %.3lf s",(1.0*clock()-st)/CLOCKS_PER_SEC);
return 0;
}