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

题目链接:传送门

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

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

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

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

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

毒瘤代码

#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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值