「NOI2017」游戏 解题报告

「NOI2017」游戏

\(d\)这么小,你考虑直接对\(d\)个东西暴力

枚举\(x\)\(a\)\(b\)\(c\)就不用了,因为\(a,b\)已经包含\(c\))了,剩下的就是个\(2-sat\)问题了

但是你发现有个情况是,在若\(A\)\(B\)时,如果\(B\)\(ban\)了,那么\(A\)也要被\(ban\)

我们记录一下被\(ban\)的点,然后在球方案的时候判一下(不得不用topo排序了..

但是其实也可以\(A\)\(\lnot A\),就可以直接比较SCC编号大小搞方案了


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <algorithm>
using std::min;
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
//#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
#define gc() getchar()
template <class T>
void read(T &x)
{
	x=0;char c=gc();
	while(!isdigit(c)) c=gc();
	while(isdigit(c)) x=x*10+c-'0',c=gc();
}
template <class T>
void reads(T &x)
{
	char c=gc();
	while(c<'a'||c>'z') c=gc();
	x=c-'a'+1;
}
template <class T>
void readb(T &x)
{
	char c=gc();
	while(c<'A'||c>'Z') c=gc();
	x=c-'A'+1;
}
const int N=2e5+10;
int head[N],to[N],Next[N],cnt;
void add(int u,int v)
{
	to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
struct _toki
{
	int a,b,c,d;
}toki[N];
int n,m,_n,yuu[N][4],ops[N],saki[N];
int val[N],ban[N],Ban[N],q[N],bel[N],opsi[N];
int low[N],dfn[N],in[N],sta[N],tot,dfsclock;
std::vector <int> E[N];
void tarjan(int now)
{
	dfn[now]=low[now]=++dfsclock;
	in[sta[++tot]=now]=1;
	for(int v,i=head[now];i;i=Next[i])
	{
		if(!dfn[v=to[i]])
		{
			tarjan(v);
			low[now]=min(low[now],low[v]);
		}
		else if(in[v])
			low[now]=min(low[now],dfn[v]);
	}
	if(low[now]==dfn[now])
	{
		int k;++_n;
		do
		{
			k=sta[tot--];
			in[k]=0;
			bel[k]=_n;
		}while(now!=k);
	}
}
int solve()
{
	memset(head,0,sizeof head);cnt=0;
	memset(ban,0,sizeof ban);
	memset(Ban,0,sizeof Ban);
	for(int a,b,c,d,i=1;i<=m;i++)
	{
		a=toki[i].a,b=toki[i].b,c=toki[i].c,d=toki[i].d;
		if(saki[a]==b) continue;
		if(saki[c]==d)
		{
			ban[yuu[a][b]]=1;
			continue;
		}
		add(yuu[a][b],yuu[c][d]);
		add(ops[yuu[c][d]],ops[yuu[a][b]]);
	}
	memset(in,0,sizeof in);
	memset(dfn,0,sizeof dfn);
	memset(low,0,sizeof low);
	memset(bel,0,sizeof bel);
	memset(opsi,0,sizeof opsi);
	_n=dfsclock=0;
	for(int i=1;i<=n<<1;i++)
		if(!dfn[i])
			tarjan(i);
	for(int i=1;i<=n;i++)
		if(bel[i]==bel[i+n])
			return -1;
	memset(val,-1,sizeof val);
	for(int i=1;i<=_n;i++) E[i].clear();
	//int ecnt=0;
	for(int u=1;u<=n<<1;u++)
	{
		for(int v,i=head[u];i;i=Next[i])
			if(bel[u]!=bel[v=to[i]])
				E[bel[v]].push_back(bel[u]),++in[bel[u]];//++ecnt;
		Ban[bel[u]]|=ban[u];
		opsi[bel[u]]=bel[ops[u]];
	}
	int l=1,r=0;
	for(int i=1;i<=_n;i++)
		if(!in[i]&&!Ban[i])
			q[++r]=i;
	while(l<=r)
	{
		int now=q[l++];
		if(val[now]==-1) val[now]=0,val[opsi[now]]=1;
		for(int v,i=0;i<E[now].size();i++)
		{
			v=E[now][i];
			--in[v];
			if(!in[v]&&!Ban[v]) q[++r]=v;
		}
	}
	for(int i=1;i<=n;i++)
		if(val[bel[i]]==-1)
			return -1;
	for(int i=1;i<=n;i++)
	{
	    int x=val[bel[i]];
		for(int j=1;j<=3;j++)
		{
			if(saki[i]!=j)
			{
				if(!x) putchar('A'+j-1);
				--x;
			}
		}
		//puts("");
	}
	return 0;
}
int main()
{
    //freopen("game.in","r",stdin);
    //freopen("game.out","w",stdout);
    int d,yuy[10];
	read(n),read(d);
	d=0;
	for(int i=1;i<=n;i++)
	{
	    ops[i]=i+n;
		ops[i+n]=i;
		reads(saki[i]);
		if(saki[i]==24)
		{
			yuy[++d]=i;
			continue;
		}
		int aya=i;
		for(int j=1;j<=3;j++)
		{
			if(saki[i]!=j)
			{
				yuu[i][j]=aya;
				aya+=n;
			}
		}
	}
	read(m);
	for(int i=1;i<=m;i++) read(toki[i].a),readb(toki[i].b),read(toki[i].c),readb(toki[i].d);
	if(!d)
	{
		if(solve()==-1) puts("-1");
		return 0;
	}
	for(int s=0;s<1<<d;s++)
	{
		for(int i=1;i<=d;i++)
		{
			if(!(s>>i-1&1))
			{
				saki[yuy[i]]=1;
				yuu[yuy[i]][2]=yuy[i];
				yuu[yuy[i]][3]=yuy[i]+n;
			}
			else
			{
				yuu[yuy[i]][1]=yuy[i];
				saki[yuy[i]]=2;
				yuu[yuy[i]][3]=yuy[i]+n;
			}
		}
		if(~solve()) return 0;
	}
	puts("-1");
	return 0;
}

2019.6.2

posted @ 2019-06-02 20:01  露迭月  阅读(232)  评论(0编辑  收藏  举报