LOJ#2305 [NOI2017]游戏 2-sat好题qwq

99封情书 提交于 2019-11-26 17:41:38

题目链接:传送门

2sat2-sat好题。
因为d8d\leq8,所以珂以考虑暴莉O(2d)O(2^d)枚举所有的x。
发现这里’x’取’a’或’b’,就能包含这一位选A/B/CA/B/C的情况,所以只用枚举两种就珂以了qwq。
暴莉枚举完后,得到一个确定的字符串strstr
然后考虑把这个问题转化成依赖性问题:
对于字符串上的每一位,建三个节点,分别表示选A,B,CA,B,C
对于每个要求(x,hx,y,hy)(x,h_x,y,h_y)分类讨论。

(1)hx==str[x]h_x==str[x]
即这个要求不可能被实现,珂以跳过。

(2)hy==str[y]h_y==str[y]
也就是说,位置yy不能选hy.h_y.
因为如果位置xxhxh_x,位置yy就一定要选hyh_y,所以位置xx不能选hxh_x
考虑怎样强制让位置xx不选hxh_x
假设位置xx除了hxh_x能选的另一个字符为tt,则从hxh_xtt连一条边。
这样如果选了hxh_x,那么hxh_x一定和tt在同一个强连通分量,是矛盾的。
所以就相当于强制选tt

(3)hx!=str[x]h_x!=str[x]hy!=str[y]h_y!=str[y]
这是一般情况,按照普通的2sat2-sat套路,对“若选A,则选B”和“若不选B,则不选A”建边即可qwq。

建完边就大莉跑2sat2-sat就珂以了qwq
注:这题因为每个点有33中情况,所以对字符的处理很臭。

毒瘤代码

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<vector>
#include<cctype>
#define re register int
#define rl register ll
#define lowbit(x) x&(-x)
using namespace std;
typedef long long ll;
int read() {
	re x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9') {
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9') {
		x=10*x+ch-'0';
		ch=getchar();
	}
	return x*f;
}
inline void write(int x) {
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
inline char GetChar() {
	char ch=getchar();
	while(ch!='A' && ch!='B' && ch!='C')	ch=getchar();
	return ch;
}
namespace I_Love {

const int Size=300005;
int n,m,d,x[Size],y[Size];
char hx[Size],hy[Size];
char str[Size];
int pos[15];
void oper(int x) {
	for(re i=1; i<=d; x>>=1,i++) {
		if(x&1) {
			str[pos[i]]='A';
		} else {
			str[pos[i]]='B';
		}
	}
}
int cnt,head[Size<<1];
struct Edge {
	int v,next;
} w[Size<<2];
void AddEdge(int u,int v) {
	w[++cnt].v=v;
	w[cnt].next=head[u];
	head[u]=cnt;
}
inline char getpre(char ch) {
	if(ch=='A')	return 'B';
	return 'A';
}
inline char getnxt(char ch) {
	if(ch=='C')	return 'B';
	return 'C';
}
inline int getid(int x,char ch) {
	if(x>n) x-=n; if(x>n) x-=n;
	if(ch=='A')	return x;
	if(ch=='B')	return x+n;
	return x+(n<<1);
}
inline char getother(int x,char ch) {
	char now=str[x];
	if(now=='A')	return (int)'B'+'C'-ch;
	if(now=='B')	return (int)'A'+'C'-ch;
	return (int)'A'+'B'-ch;
}
int tim,top,tot,dfn[Size],stk[Size],belong[Size],low[Size];
bool vis[Size];
void Tarjan(int x) {
	dfn[x]=low[x]=++tim;
	stk[++top]=x;
	vis[x]=true;
	for(int i=head[x]; i; i=w[i].next) {
		int nxt=w[i].v;
		if(!dfn[nxt]) {
			Tarjan(nxt);
			low[x]=min(low[x],low[nxt]);
		} else if(vis[nxt]) {
			low[x]=min(low[x],dfn[nxt]);
		}
	}
	if(low[x]==dfn[x]) {
		int y;
		tot++;
		while(y=stk[top--]) {
			belong[y]=tot;
			vis[y]=false;
			if(x==y)	return;
		}
	}
}
char ans[Size];
void Fujibayashi_Ryou() {
//	freopen("game16.in","r",stdin);
//	freopen("WA.txt","w",stdout);
	n=read();
	d=read();
	scanf("%s",str+1);
	m=read();
	for(re i=1; i<=m; i++) {
		x[i]=read();
		hx[i]=GetChar();
		y[i]=read();
		hy[i]=GetChar();
	}
	int now=0;
	for(re i=1; i<=n; i++) {
		if(str[i]=='x')	pos[++now]=i;
		str[i]=toupper(str[i]);
	}
	int maxn=1<<d;
	for(re i=0; i<maxn; i++) {
		oper(i);
		memset(head,0,sizeof(head)); cnt=0;
		memset(belong,0,sizeof(belong)); tot=0;
		memset(dfn,0,sizeof(dfn));
		memset(low,0,sizeof(low));
		for(re j=1; j<=m; j++) {
			if(hx[j]==str[x[j]]) {
				continue;
			} else if(hy[j]==str[y[j]]) {
				//不能让x[j]为hx[j] 
				AddEdge(getid(x[j],hx[j]),getid(x[j],getother(x[j],hx[j])));
			} else {
				//若x[j]选了hx[j],则y[j]要选hy[j] 
				AddEdge(getid(x[j],hx[j]),getid(y[j],hy[j]));
				//若y[j]没选hy[j],则x[j]不选hx[j] 
				AddEdge(getid(y[j],getother(y[j],hy[j])),getid(x[j],getother(x[j],hx[j])));
			}
		}
		for(re j=1; j<=n*3; j++) {
			int id=j; if(id>n) id-=n; if(id>n) id-=n;
			if(getid(id,str[id])!=j && !dfn[j]) {
				Tarjan(j);
			}
		}
		bool fail=false;
		for(re j=1; j<=n; j++) {
			int t1=getid(j,getpre(str[j]));
			int t2=getid(j,getnxt(str[j]));
			if(belong[t1]==belong[t2]) {
				fail=true;
				break;
			}
			if(belong[t1]<belong[t2]) {
				ans[j]=getpre(str[j]);
			} else {
				ans[j]=getnxt(str[j]);
			}
		}
		if(!fail) {
			puts(ans+1);
			return;
		}
	}
	printf("-1");
}

}
int main() {
	I_Love::Fujibayashi_Ryou();
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!