P3825 [NOI2017]游戏

斯德哥尔摩

2018-08-01 11:13:55

Personal

[P3825 [NOI2017]游戏](https://www.luogu.org/problemnew/show/P3825) 这题好像是$NOI2017-DAY2-T1$,吓得我瑟瑟发抖不敢做。。。 艰难地看完题目,嗯?有限制条件的$2-SAT$? 想了想,好像可行。 然而$2-SAT$不会敲。。。 可以发现,除了$x$地图之外,其余的地图只适合两种赛车。 我们先假设所有的地图都适合且只适合两种赛车,这样就是$2-SAT$裸题了。 对于每场游戏用两个点$i$和$i'$,分别表示第$i$场游戏使用该地图适合的第一种赛车和第二种赛车。 煮个栗子:如果第$i$场游戏的地图不适合$A$赛车,那么点$i$表示第$i$场游戏使用$B$赛车,点$i'$表示第$i$场游戏使用$C$赛车。 对于每个限制条件,设$u$表示第$i$场游戏使用型号为$h_i$的赛车的点(在第$i$场游戏的地图适合型号为$h_i$的赛车的情况下),$v$为表示第$j$场游戏使用型号为$h_j$的赛车的点(在第$j$场游戏的地图适合型号为$h_j$的赛车的情况下)。 那么分类讨论: 1. 如果第$i$场游戏的地图不适合型号为$h_i$的赛车: 不做任何操作。 2. 如果第$i$场游戏的地图适合型号为$h_i$的赛车,但第$j$场游戏的地图不适合型号为$h_j$的赛车: 建边$u->u'$,表示如果第$i$场游戏使用了型号为$h_i$的赛车则一定无解。 3. 如果第$i$场游戏的地图适合型号为$h_i$的赛车,第$j$场游戏的地图适合型号为$h_j$的赛车: 建边$u->v$,表示如果第$i$场游戏使用了型号为$h_i$的赛车则第$j$场游戏必须使用型号为$h_j$的赛车。 再建边$v'->u'$,表示如果第$j$场游戏不使用型号为$h_j$的赛车则第$i$场游戏不得使用型号为$h_i$的赛车。 当所有边都建完之后跑一遍$Tarjan$强连通分量缩点。 若存在一对$i$和$i'$在同一个强连通分量里面——无解。 否则输出方案。 $2-SAT$输出方案的方法: 先把缩点之后的新图进行拓扑排序,然后判断每个点$i$,如果$i$所在强连通分量的拓扑序在$i'$所在的强连通分量的拓扑序之后,那么第$i$场游戏使用该地图适合的第一种赛车,否则使用第二种赛车。 但是我不想再拓扑排序了,怎么办? 这里,由于$Tarjan$求强连通分量就是按拓扑排序的逆序给出的,所以直接使用强连通分量编号判断即可。 即:若$colour[i]<colour[i']$,那么使用该地图适合的第一种赛车,否则使用第二种赛车。($colour[i]$为每个点的所在强连通分量的染色编号。) 好神奇! 现在考虑$x$地图,考虑到最多只有$8$张$x$地图,如果假设它也只适合两种赛车,那么暴力枚举每个$x$地图不适合赛车$A$或不适合赛车$B$。 因为不适合赛车$A$就是适合赛车$B,C$,不适合赛车$B$就是适合赛车$A,C$,这样就包含了$A,B,C$三种赛车。 这样每种地图就都只适合两种赛车了。 判断时,如果已经枚举遍了所有的$2^d$种状态都是无解,则原问题无解,否则输出任意一种方案。 复杂度?当然$O((n+m)* 2^d)$。 附代码: ```cpp #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 200010 using namespace std; int n,m,k; int pos[MAXN]; char s[MAXN],choose[MAXN]; bool flag=false; struct Limit{ int i,j; char x,y; }a[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } namespace Tarjan{ int c=1,d=1,top=1,num=0; int cstack[MAXN],head[MAXN],deep[MAXN],low[MAXN],colour[MAXN]; bool vis[MAXN]; struct Graph{ int next,to; }edge[MAXN]; inline void add(int x,int y){ edge[c].to=y;edge[c].next=head[x];head[x]=c++; } void dfs(int x){ deep[x]=low[x]=d++; vis[x]=true; cstack[top++]=x; for(int i=head[x];i;i=edge[i].next){ int v=edge[i].to; if(!deep[v]){ dfs(v); low[x]=min(low[x],low[v]); } else if(vis[v])low[x]=min(low[x],deep[v]); } if(low[x]==deep[x]){ num++; do{ colour[cstack[top-1]]=num; vis[cstack[top-1]]=false; }while(cstack[--top]!=x); } } inline int point(int x){return (x>n?(x-n):(x+n));} inline int change(int x,char ch){ if(s[x]=='a')return (ch=='B'?x:(x+n)); if(s[x]=='b'||s[x]=='c')return (ch=='A'?x:(x+n)); if(ch=='C')return (x+n); return x; } void init(){ c=d=top=1; num=0; memset(head,0,sizeof(head)); memset(deep,0,sizeof(deep)); memset(low,0,sizeof(low)); memset(colour,0,sizeof(colour)); } bool solve(){ init(); for(int i=1;i<=m;i++){ if(s[a[i].i]!='x'&&s[a[i].j]!='x'){ if(a[i].x==s[a[i].i]-32)continue; int u=change(a[i].i,a[i].x); if(a[i].y==s[a[i].j]-32)add(u,point(u)); else{ int v=change(a[i].j,a[i].y); add(u,v); add(point(v),point(u)); } } else{ int x=pos[a[i].i],y=pos[a[i].j]; if(s[a[i].i]=='x'&&s[a[i].j]=='x'){ if(a[i].x==choose[x])continue; int u=change(a[i].i,a[i].x); if(a[i].y==choose[y])add(u,point(u)); else{ int v=change(a[i].j,a[i].y); add(u,v); add(point(v),point(u)); } } else if(s[a[i].i]=='x'&&s[a[i].j]!='x'){ if(a[i].x==choose[x])continue; int u=change(a[i].i,a[i].x); if(a[i].y==s[a[i].j]-32)add(u,point(u)); else{ int v=change(a[i].j,a[i].y); add(u,v); add(point(v),point(u)); } } else{ if(a[i].x==s[a[i].i]-32)continue; int u=change(a[i].i,a[i].x); if(a[i].y==choose[y])add(u,point(u)); else{ int v=change(a[i].j,a[i].y); add(u,v); add(point(v),point(u)); } } } } for(int i=1;i<=(n<<1);i++)if(!deep[i])dfs(i); for(int i=1;i<=n;i++)if(colour[i]==colour[i+n])return false; for(int i=1;i<=n;i++){ if(colour[i]<colour[i+n]){ if(s[i]=='a')printf("B"); else if(s[i]=='b'||s[i]=='c')printf("A"); else if(choose[pos[i]]=='A')printf("B"); else printf("A"); } else{ if(s[i]=='a'||s[i]=='b')printf("C"); else if(s[i]=='c')printf("B"); else if(choose[pos[i]]=='A')printf("C"); else printf("B"); } } return true; } } void dfs(int x){ if(flag)return; if(x>k){ if(!flag)flag=Tarjan::solve(); if(flag)return; return; } choose[x]='A';dfs(x+1); if(flag)return; choose[x]='B';dfs(x+1); return; } void work(){ dfs(1); if(!flag)printf("-1\n"); } void init(){ char ch[2]; n=read();k=read(); scanf("%s",s+1); for(int i=1,j=1;i<=n;i++)if(s[i]=='x')pos[i]=j++; m=read(); for(int i=1;i<=m;i++){ a[i].i=read();scanf("%s",ch); a[i].x=ch[0]; a[i].j=read();scanf("%s",ch); a[i].y=ch[0]; } } int main(){ init(); work(); return 0; } ```