[NOI2017]游戏
题目描述
http://www.lydsy.com/JudgeOnline/upload/Noi2017D2.pdf
题解
如果说没有x的话,那么每一局只能有两种选择,可以描述为是/非,每条限制也可以描述是x即y。
那么这就是一道经典的2-SAT问题。
现在有了x的限制,但是观察到x的数目很少最多只有8,所以我们可以考虑枚举限制。
注意到其他的地方有两种情况是因为有一种情况被ban了,所以我们考虑枚举2^x枚举该局禁哪个,因为禁A和禁B已经可以包含所有的情况,所以就不用禁C了。
仅为有ban的存在,所以我们在处理限制的时候要注意,如果某个位置连向的位置被ban了,那么直接连x->x‘表示x不合法。
代码
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define M 100002 #define N 50002 using namespace std; char s[N],ss[1]; int head[M],st[M],top,low[M],dfn[M],tot,co[M],num,ban[N],jin[N],n; bool vis[M]; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct node{ int x,y,xx,yy; }b[M]; struct edge{int n,to;}e[M<<1]; inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;} void tarjan(int u){ vis[u]=1;st[++top]=u;low[u]=dfn[u]=++dfn[0]; for(int i=head[u];i;i=e[i].n){ int v=e[i].to; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ ++num;int x; do{ x=st[top]; vis[x]=0; co[x]=num; top--; } while(x!=u); } } int main(){ n=rd();int d=rd(); scanf("%s",s+1); for(int i=1;i<=n;++i){ if(s[i]=='x')jin[++jin[0]]=i; else if(s[i]=='a')ban[i]=1; else ban[i]=0; s[i]-='a'; } int m=rd(); for(int i=1;i<=m;++i){ b[i].x=rd();scanf("%s",ss);b[i].xx=ss[0]-'A'; b[i].y=rd();scanf("%s",ss);b[i].yy=ss[0]-'A'; } for(int i=0;i<(1<<d);++i){ for(int j=1;j<=jin[0];++j){ int x=(i&(1<<j-1))!=0; if(x)s[jin[j]]=0,ban[jin[j]]=1; else s[jin[j]]=1,ban[jin[j]]=0; } memset(head,0,sizeof(head));tot=0; for(int j=1;j<=m;++j){ if(s[b[j].x]==b[j].xx)continue; int nowx,nowy,antix,antiy; nowx=(b[j].xx==ban[b[j].x])?b[j].x:b[j].x+n;antix=nowx<=n?nowx+n:nowx-n; if(s[b[j].y]==b[j].yy){ add(nowx,antix);continue; } nowy=(b[j].yy==ban[b[j].y])?b[j].y:b[j].y+n;antiy=nowy<=n?nowy+n:nowy-n; add(nowx,nowy); add(antiy,antix); } memset(dfn,0,sizeof(dfn));num=0; for(int j=1;j<=n*2;++j)if(!dfn[j])tarjan(j); bool ta=0; for(int j=1;j<=n;++j)if(co[j]==co[j+n]){ta=1;break;} if(ta)continue; for(int j=1;j<=n;++j)if(co[j]<co[j+n]){ if(ban[j]==1)printf("B"); else printf("A"); } else{ if(ban[j]==1)printf("C"); else if(s[j]==1)printf("C");else printf("B"); } return 0; } printf("-1"); return 0; }