P3825 [NOI2017] 游戏

Link

不禁让人加深了对 2-SAT 的感知度。

先考虑 d=0d=0 的情况,这时候发现每个赛道其实只有两种取值,所以可以考虑 2-SAT,具体的,把每个点能取的两种取值看成 0011,然后按照题目的限制连边即可。

然后发现 dd 的范围很小,不难想到暴力取 x 的点应该用什么赛车,时间复杂度是 O(3d×(n+m))O(3^d \times (n+m)) 的,难以通过。

不妨想到我们最开始 d=0d=0 的时候,我们定义了一个点是有两种取值的,比如说当前赛道是 a,实际上我们就已经把使用了赛车 BC 都考虑进去了,所以我们只需要枚举两种赛道,这样就能覆盖到取三种赛车的情况。

这样的话时间复杂度就被优化到了 O(2d×(n+m))O(2^d \times (n+m)),可以通过本题。

细节不少,注意每次跑的时候清空要完全,以及在连边的时候的判断情况要想清楚。

#include<bits/stdc++.h>
using namespace std;
const int N =2e5+10;
vector<int> g[N];
char s[N],ans[N],ch[N],ch1[N];
int low[N],dfn[N],vis[N],F[N],tot,SCC;
int n,m,d,op[N],op1[N];
stack<int> sta;
bool f=false;
int change(char Ch,int dis){
	if(s[dis]=='a')	return ((Ch=='B')?dis:dis+n);
	else if(s[dis]=='b')	return ((Ch=='A')?dis:dis+n);
	else	return ((Ch=='A')?dis:dis+n);
}
void build(){
	for(int i=1;i<=m;i++){
		int u=change(ch[i],op[i]),v=change(ch1[i],op1[i]);
		if(ch[i]==s[op[i]]-'a'+'A')	continue;
		if(ch1[i]==s[op1[i]]-'a'+'A')	g[u].push_back(((u>n)?u-n:u+n));
		else 	g[u].push_back(v),g[((v>n)?v-n:v+n)].push_back((u>n)?u-n:u+n);
	}
}
void Clear(){
	for(int i=1;i<=2*n;i++)	g[i].clear(),low[i]=dfn[i]=0,F[i]=0,vis[i]=0;
	SCC=tot=0; 
}
void Tarjan(int u){
	dfn[u]=low[u]=++tot,vis[u]=1,sta.push(u);
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(!dfn[v])	Tarjan(v),low[u]=min(low[u],low[v]);
		else if(vis[v]==1)	low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u]){
		SCC++;
		while(!sta.empty()&&sta.top()!=u)	F[sta.top()]=SCC,vis[sta.top()]=2,sta.pop();
		F[sta.top()]=SCC,vis[sta.top()]=2,sta.pop();
	}
}
void Slove(){
	build();
	for(int i=1;i<=2*n;i++)	if(!dfn[i])	Tarjan(i);
	for(int i=1;i<=n;i++)	if(F[i]==F[i+n])	{Clear();return ;}
	for(int i=1;i<=n;i++){
		if(s[i]=='a')	ans[i]=((F[i]>F[i+n])?'C':'B');
		else if(s[i]=='b')	ans[i]=((F[i]>F[i+n])?'C':'A');
		else	ans[i]=((F[i]>F[i+n])?'B':'A');
	}
	Clear(),f=true;
}
void dfs(int dis){
	if(dis==n+1){Slove();return ;}
	if(s[dis]=='x')	s[dis]='a',dfs(dis+1),s[dis]='b',dfs(dis+1),s[dis]='x';
	else	dfs(dis+1);
}
int main(){
	cin>>n>>d,scanf("%s",s+1),cin>>m;
	for(int i=1;i<=m;i++)	cin>>op[i]>>ch[i]>>op1[i]>>ch1[i];
	dfs(1);	
//	Slove();
//	for(int i=1;i<=2*n;i++)	cout<<F[i]<<" ";
	if(f==false)	cout<<-1<<endl,exit(0);
	else	for(int i=1;i<=n;i++)	cout<<ans[i];
}
posted @   June_Failure  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示