【BZOJ3880】炼辰 有向有环有限制的博弈 我是出题人!

转载请注明出处谢谢:blog.csdn.net/vmurder/article/details/42968425

诶那个什么94.net这篇题解你要是转载别删出处了谢谢。。。

我再处理一下嘿嘿。blog。csdn。net|vmurder|article|details|42968425

。是.

|是/

做个实验:看看它的转载机制会不会把代码都删除

#include <cstdio>
using namespace std;
int main()
{
	puts("blog.csdn.net/vmurder/article/details/42968425");
}



嗯,这是一道原创题。

然后下面贴的是我当时写的题解。

本来以为在BZOJ上面晒一段时间可以有人去花时间想一想这道题。

但是貌似我想多了。。。


{

这道题显然是一道博弈题,然后因为环断了一个点,所以不妨先把它处理成一条链。这道题我对于数据规定了一种性质:任意两条边不相交。这样就大有可做了。

首先我们思考,从起点出发,那么因为每到一个点,之前的点就都走过了,所以现在无法通过边回头,那么也就是说,当总点数(别忘了刨去那一个断点)是奇数的时候,直接从1出发,就可以保证必胜。

那么总点数是偶数怎么办呢?好说,我们直接从第二个点出发就行了,真的行么?这个时候却会出现一个问题,就是往前走,可能有某个点可以回到1,这样先手就输了,所以想得这么简单是不行的。

这道题限定了边不“交叉”,所以链一定可以被划分成若干个(可以只有1个)独立的区间,而我们从每个区间的开头出发,就不可能再回到之前的节点。

而我们如果从一段区间的中间出发,那么我们至多沿着某边回溯一次,然后就需要一直往前走,而开始节点的前一个节点,则是一个必胜节点。

这个时候我们进行讨论:(节点总数为偶,不然直接出解)

---------------------------------------------------

一、从奇点出发,先手可以选择在偶点回溯,如果此偶点可以回到偶点,即胜。而我们还需要保证在奇点对方无法回到偶点。

二、从偶点出发,先手可以选择在奇点回溯,如果此奇点可以回到奇点,即胜。而我们还需要保证在偶点对方无法回到奇点。

--------------------------------------------------

注意到上面两种情况,从奇点出发则必须回溯,而偶点则不然。所以我们可以特判一个区间的结束节点:

如果结束节点是偶,且不能回到奇点,那么必胜。

如果结束节点是奇,那我们不可以在结束节点开始,否则对方只需要往前一步,我们就输了,且无法逆转。

特判了结束节点以后,我们可以发现,如果我们可以在某个节点回溯,并且取得胜利,那么从开始节点到这个节点这一段区间,对方是不可以有逆转的机会的(奇点回偶/偶点回奇),这样我们不妨把开始节点无限右推,推到回溯节点前一位。

然后对于每段区间,我们只需要枚举回溯节点,然后check一下它的上一个节点是否可以逆转,就可以出解了。

显然这样扫一遍,发现所有的节点都是必败,那么这场博弈就输了,这样就只能输出“污得不行”了。

细节:我们记录了每个点能否回溯到奇/偶点,但是有可能能回溯,check却已经被堵?不可能。

因为奇需要回到奇,而我们是从它前一个点(偶)开始的,而偶则亦然。

 

话说这道题可以记忆化深搜水过么?如果可以,那么思路应该是只需要判断某个节点如果是一段区间的开始节点,那么它就只能往前走,不能回头,故它是一个结束节点,然后就可以记忆化进行推演了。

但是这道题中,一个节点并不是有出边就可以走的,,而状态压缩,更是活在梦里,随意YY了一下,感觉并不能这么水过。

我又想了一下,发现记忆化搜索的话你不知道那些点能走,哪些点不能,比如偶环套偶环,外面的偶环你倒是可以直接根据奇偶性判断胜负,里面的环呢?233。不需要卡!因为它本身就没法搜!要记忆化,只能先枚举开始点,(这样貌似依然不可行),然后再搜,即使可行,也是n^2的,显然TLE 了。。。

}

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1001000
using namespace std;
int n,m,vv[N],cnt;
bool jd[N][2];
void build_chain()
{
	int a,b,c;
 
	scanf("%d%d%d",&n,&m,&c);
	for(int i=1;i<n;i++)vv[i]=i;
	while(m--)
	{
		scanf("%d%d",&a,&b);
		if(a==b||a==c||b==c)continue;
		a=(a+n-c)%n,b=(b+n-c)%n;
		if(a<b)
		{
			vv[a]=max(vv[a],b);
			jd[b][a&1]=1;
		}
		else
		{
			vv[b]=max(vv[b],a);
			jd[a][b&1]=1;
		}
	}
	n--;
}
int l[N],r[N];
bool build_district()
{
	for(int i=1;i<=n;i++)
	{
		cnt++;
		if(vv[i]==i)return 1;
		l[cnt]=i;
		r[cnt]=i=vv[i];
	}
	return 0;
}
bool check(int f)
{
	if((r[f]&1)==0&&jd[r[f]][1]==0)return 1;
	for(int i=l[f]+1;i<=r[f];i++)
	{
		if((i&1)&&jd[i][1])
			if(jd[i-1][1]==false)return 1;
		if((i%2==0)&&jd[i][0])
			if(jd[i-1][0]==false)return 1;
	}
	return 0;
}
int main()
{
	build_chain();
	if(!n)
	{
		puts("galaxy");
		return 0;
	}
	if((n&1)||build_district()==1)
	{
		puts("dawn");
		return 0;
	}
	for(int i=1;i<=cnt;i++)
	{
		if(check(i))
		{
			puts("dawn");
			return 0;
		}
	}
	puts("galaxy");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值