[NOI2017] 游戏 题解
发现 \(x\) 只有 \(8\) 个,想到暴力枚举每个 \(x\) 是 \(b\) 还是 \(c\)(这样就将 \(ABC\) 全覆盖了),时间复杂度 \(\times 2^d\),可以接受。
考虑建边。建边可以分为 \(3\) 种情况:
- \(i\) 本身就不能选 \(h_i\)。那这条要求就是没用的。
- \(i\) 可以选 \(h_i\),但 \(j\) 不能选 \(h_j\)。这种情况下,\(i\) 选了 \(h_i\) 就是死路一条,所以 \(i\to !i\)。
- \(i,j\) 可以选 \(h_i,h_j\)。这种情况下连 \(i\to j,!j\to !i\) 即可。
时间复杂度 \(O(2^d(n+m))\)。
#include<bits/stdc++.h>
#define f1(a,x,y,z) a[0]=x,a[1]=y,a[2]=z
#define f2(a,x,y) a[0]=x,a[1]=y
using namespace std;
const int N=50005,M=1e5+5;string s;
int n,d,m,mp[N][3],cl[N][2];vector<int>g[M];
struct rule{int x,cx,y,cy;}rl[M];int al[10];
int id,cnt,tp,dfn[M],low[M],st[M],vs[M],idx[M];
void tarjan(int x){
dfn[x]=low[x]=++id,vs[st[++tp]=x]=1;
for(auto y:g[x]){
if(!dfn[y]) tarjan(y),low[x]=min(low[x],low[y]);
else if(vs[y]) low[x]=min(low[x],dfn[y]);
}if(dfn[x]!=low[x]) return;cnt++;
while(st[tp+1]!=x) idx[st[tp]]=cnt,vs[st[tp--]]=0;
}int oth(int x){return (x+n-1)%(n+n)+1;}
void solve(){
for(int i=1;i<=2*n;i++) g[i].clear();
for(int i=1;i<=m;i++){
int x=rl[i].x,y=rl[i].y,cx=rl[i].cx,cy=rl[i].cy;
if(mp[x][cx]<0) continue;int ix=x+n*mp[x][cx],iy=y+n*mp[y][cy];
if(mp[y][cy]<0) g[ix].push_back(oth(ix));
else g[ix].push_back(iy),g[oth(iy)].push_back(oth(ix));
}for(int i=1;i<=2*n;i++) dfn[i]=low[i]=vs[i]=0;id=cnt=0;
for(int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++) if(idx[i]==idx[i+n]) return;
for(int i=1;i<=n;i++) cout<<(char)(cl[i][idx[i]>idx[i+n]]+'A');exit(0);
}int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>d>>s>>m,s=" "+s;
for(int i=1;i<=m;i++){
char c,h;cin>>rl[i].x>>c>>rl[i].y>>h;
rl[i].cx=c-'A',rl[i].cy=h-'A';
}for(int i=1,t=0;i<=n;i++){
if(s[i]=='x') al[t++]=i,cl[i][0]=0;
if(s[i]=='a') f1(mp[i],-1,0,1),f2(cl[i],1,2);
if(s[i]=='b') f1(mp[i],0,-1,1),f2(cl[i],0,2);
if(s[i]=='c') f1(mp[i],0,1,-1),f2(cl[i],0,1);
}for(int i=0;i<(1<<d);i++){
for(int j=0;j<d;j++){
if((i>>j)&1) f1(mp[al[j]],0,-1,1),cl[al[j]][1]=2;
else f1(mp[al[j]],0,1,-1),cl[al[j]][1]=1;
}solve();
}cout<<-1;
return 0;
}

浙公网安备 33010602011771号