loj#2305. 「NOI2017」游戏 2-sat

链接

https://loj.ac/problem/2305
https://www.luogu.org/problemnew/show/P3825

思路

3-sat神马的就不要想了,NP问题
除去x每个点只有两种可能,2-sat
x只有8个,\(3^n\)暴力枚举哪个不选
2-sat是对称性的
当起点x的战车不存在,continue
else 当终点的战车不存在,那么起点战车也不能选呀(选了就G了呀),起点连向剩下的那个可选点
else 起点终点都还在,连起来,否逆命题:原命题为:若a,则b。逆否命题为:若非b,则非a。
所以他俩的兄弟还要连一条边
但是计算一下发现,有点小超时呀
其实只要枚举A和B(随便两个)就好了
因为一个点最终只会用一辆车呀(有一辆就是个摆设)
\(2^n\)已经把所有可以选的情况整出来了
然后开心的\(O(2^n(n+m))\)

其他的

难道我天生就是制造bug的吗


后记:
uojTLE1个(貌似要随机化,输出,不管了)
luoguwrong1个(spj没判回车)
bzojok
lojok

代码

#include <bits/stdc++.h>
using namespace std;
const int N=3e5+7;
int read() {
	int x=0,f=1;char s=getchar();
	for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
	for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
	return x*f;
}
int n,m,d,head[N<<2],tot;
int top,cnt,stak[N],low[N],dfn[N],belong[N];
bool vis[N],Choose[N];
char s[N],S[N];
struct node {
	int v,nxt;
}e[N<<2];
struct edge {
	int i,x,j,y;
}ABC[N];
void add(int u,int v) {
	swap(u,v);
	e[++tot].v=v;
	e[tot].nxt=head[u];
	head[u]=tot;
}
void tarjan(int u) {
	low[u]=dfn[u]=++cnt;
	stak[++top]=u;
	vis[u]=1;
	for(int i=head[u];i;i=e[i].nxt) {
		int v=e[i].v;
		if(!dfn[v]) {
			tarjan(v);
			low[u]=min(low[u],low[v]);
		} else if(vis[v]) {
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u]) {
		++belong[0];
		while(stak[top]!=u) {
			vis[stak[top]]=0;
			belong[stak[top]]=belong[0];
			top--;
		} top--;
		vis[u]=0;
		belong[u]=belong[0];
	}
}
void Clear() {
	memset(head,0,sizeof(head));
    memset(low,0,sizeof(low));
    memset(dfn,0,sizeof(dfn));
    memset(vis,0,sizeof(vis));
    memset(belong,0,sizeof(belong));
	cnt=top=tot=belong[0]=0;
}
int mmp[5][2]={ {1,2},
			    {0,2},
			 	{0,1},};
void solve() {
	int js=1;
	for(int i=1;i<=n;++i) {
		if(s[i]=='x'-'a') {
			if(Choose[js]==0) S[i]=0;
			else S[i]=1;
		} else S[i]=s[i];
	}
    for(int i=1;i<=m;++i) {
    	if(ABC[i].x==S[ABC[i].i]) continue;
    	int tmp_1= (mmp[S[ABC[i].i]][1]==ABC[i].x) ? mmp[S[ABC[i].i]][0] : mmp[S[ABC[i].i]][1];
		int tmp_2= (mmp[S[ABC[i].j]][1]==ABC[i].y) ? mmp[S[ABC[i].j]][0] : mmp[S[ABC[i].j]][1];
    	if(ABC[i].y==S[ABC[i].j]) add(ABC[i].i+n*ABC[i].x,ABC[i].i+n*tmp_1);
		else {
			add(ABC[i].i+n*ABC[i].x,ABC[i].j+n*ABC[i].y);
			add(ABC[i].j+n*tmp_2,ABC[i].i+n*tmp_1);
		}
    }
    for(int i=1;i<=3*n;++i) {
    	// if(S[(i-1)/3+1]==(i+2)%3) continue;一定没有这一句
    	if(!dfn[i])
			tarjan(i);
	}
	for(int i=1;i<=n;++i) {
		if(belong[i+n*(mmp[S[i]][0])]==belong[i+n*(mmp[S[i]][1])]) return;
		// if(S[i]=='a'&&belong[i+n]==belong[i+2*n]) return;
		// if(S[i]=='b'&&belong[i]==belong[i+2*n]) return;
		// if(S[i]=='c'&&belong[i]==belong[i+n]) return;
	}
	for(int i=1;i<=n;++i) {
		if(S[i]==0) {
			if(belong[i+n]>belong[i+2*n]) printf("B");
			else printf("C");
		}
		if(S[i]==1) {
			if(belong[i]>belong[i+2*n]) printf("A");
			else printf("C");
		}
		if(S[i]==2) {
			if(belong[i]>belong[i+n]) printf("A");
			else printf("B");
		}
	}
	exit(0);
}
int main() {
//	freopen("a.in","r",stdin);
	n=read(),d=read();
	for(int i=1;i<=n;++i) {
		char dd;
		scanf("%c",&dd);
		s[i]=dd-'a';
	}
	m=read();
	for(int i=1;i<=m;++i) {
		char s;
		ABC[i].i=read();
		s=getchar();
		while(s==' ') s=getchar();
		ABC[i].x= (s=='A') ? 0 : (s=='B') ? 1 : 2;
		ABC[i].j=read();
		s=getchar();
		while(s==' ') s=getchar();
		ABC[i].y= (s=='A') ? 0 : (s=='B') ? 1 : 2;
		//end
	}
	for(int i=0;i<(1<<d);++i) {
		for(int j=0;j<d;++j) Choose[j+1]=(bool)(1<<j)&i;
		Clear();
		solve();
	}
	puts("-1");
	return 0;
}

posted @ 2019-02-21 07:44  ComplexPug  阅读(155)  评论(0编辑  收藏  举报