P3825 [NOI2017] 游戏 题解

P3825 [NOI2017] 游戏

对于x,有三种选择,不符合2SAT,因此靠枚举xa,b,c来变为2SAT,但是只需要枚举任意两个即可,因为枚举为c,则a,b可选,枚举ba,c可选,三种情况都覆盖

对于建边:

u>v,但是u不合法,则无视

u>v,但是v不合法,则u>u,这样就不会选u(非法情况的处理方式)

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define inf 1e18
#define inc 0xcfcfcfcf
#define N 100007
#define M 500007
#define mod 1000000007
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
using namespace std;
struct Edge
{
	int to,nxt;
}edge[N<<1];
struct In
{
	int a,b;
	char x,y;
}in[N];
int head[N<<1],dfn[N<<1],low[N<<1],belong[N<<1];
bool vis[N<<1];
int a[N],bits[N];
int T=1,n,d,m,ecnt,bcnt,tcnt;
stack<int> stk;
void Add(int u,int v)
{
	edge[++ecnt]=(Edge){v,head[u]};
	head[u]=ecnt;
}
void Tarjan(int u)
{
	dfn[u]=low[u]=++tcnt;
	vis[u]=1;
	stk.push(u);
	for(int i=head[u];i;i=edge[i].nxt)
	{
		int v=edge[i].to;
		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])
	{
		int v;
		++bcnt;
		do
		{
			v=stk.top();
			stk.pop();
			vis[v]=0;
			belong[v]=bcnt;
		}while(u!=v);
	}
}
bool Two_sat()
{
	for(int i=1;i<=2*n;++i)
		if(!dfn[i])
			Tarjan(i);
	for(int i=1;i<=n;i++)
		if(belong[i]==belong[i+n])
			return 0;
	return 1;
}
void Init()
{
 	memset(vis,0,sizeof(vis));
 	memset(belong,0x3f,sizeof(belong));
 	memset(dfn,0,sizeof(dfn));
 	memset(low,0,sizeof(low));
 	memset(head,0,sizeof(head));
 	while(!stk.empty())
 		stk.pop();
	tcnt=bcnt=ecnt=0;
}
bool Solve()
{
	scanf("%lld%lld",&n,&d);
	string s;
	cin>>s;s=" "+s;
	int cnt=0;
	for(int i=1;i<s.size();++i)
		if(s[i]=='x')
			a[i]=cnt++;
	scanf("%lld",&m);
	for(int i=1;i<=m;++i)
		scanf("%lld %c %lld %c",&in[i].a,&in[i].x,&in[i].b,&in[i].y);
	for(int now=0;now<(1<<d);++now)
	{
		Init();
		for(int i=1;i<=m;++i)
		{
			int na=in[i].x-'A',nb=in[i].y-'A';
			int l=in[i].a,r=in[i].b;
			if(s[in[i].a]=='x') 
			{
				if(now&(1<<a[in[i].a]))
				{
					if(na==1)
						continue;
					if(na==2)
						l+=n;
				}
				else
				{
					if(na==2)
						continue;
					if(na==1)
						l+=n;
				}
			}
			else
			{
				if((s[in[i].a]-'a')==na)
						continue;
				if(s[in[i].a]=='a')
					if(na==2)
						l+=n;
				if(s[in[i].a]=='b')
					if(na==2)
						l+=n;
				if(s[in[i].a]=='c')
					if(na==1)
						l+=n;
			}
			if(s[in[i].b]=='x') 
			{
				if(now&(1<<a[in[i].b]))
				{
					if(nb==1)
					{
						Add(l,(l==in[i].a)?(l+n):(l-n));
						continue;
					}
					if(nb==2)
						r+=n;
				}
				else
				{
					if(nb==2)
					{
						Add(l,(l==in[i].a)?(l+n):(l-n));
						continue;
					}
					if(nb==1)
						r+=n;
				}
			}
			else
			{
				if((s[in[i].b]-'a')==nb)
				{
					Add(l,(l==in[i].a)?(l+n):(l-n));
					continue;
				}
				if(s[in[i].b]=='a')
					if(nb==2)
						r+=n;
				if(s[in[i].b]=='b')
					if(nb==2)
						r+=n;
				if(s[in[i].b]=='c')
					if(nb==1)
						r+=n;
			}
			Add(l,r);
			if(l==in[i].a)
				l+=n;
			else
				l-=n;
			if(r==in[i].b)
				r+=n;
			else
				r-=n;
			Add(r,l);
		}
		if(Two_sat())
		{
			for(int i=1;i<=n;++i)
			{
				if(s[i]=='x')
				{
					if(now&(1<<a[i]))
					{
						if(belong[i]<belong[i+n])
							printf("A");
						else
							printf("C");
					}
					else
					{
						if(belong[i]<belong[i+n])
							printf("A");
						else
							printf("B");
					}
				}
				if(s[i]=='a')
				{
					if(belong[i]<belong[i+n])
						printf("B");
					else
						printf("C");
				}
				if(s[i]=='b')
				{
					if(belong[i]<belong[i+n])
						printf("A");
					else
						printf("C");
				}
				if(s[i]=='c')
				{
					if(belong[i]<belong[i+n])
						printf("A");
					else
						printf("B");
				}
			}
			printf("\n");
			return 1;
		}
	}
	return 0;
}
signed main()
{
	//scanf("%lld",&T);
	while(T--)
		if(!Solve())
			printf("-1\n");
	return 0;
}


posted @   模拟退火  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示