bzoj3440: 传球游戏

8 篇文章 0 订阅

这不傻逼题吗!

一开始连题目都被读懂。。。

第1类人,顺着传来的方向传给下一个人。
第2类人,逆着传来的方向传给上一个人。
第3类人,顺着传来的方向传给下面第二个人。
第4类人,逆着传来的方向传给上面第二个人。
不知是从哪个人开始传,及开始传的方向,求有哪些人无论如何最多只能碰到一次球
然后很容易想到拆点,然后找环,可是不止有这种情况,可以从1号顺时针走到2号顺时针再走到1号逆时针,1号也算走了2次。。。

于是删程序继续码码码,终于A了。


#include<iostream>
#include<cstdio>
#define N 1000005
using namespace std;
int LY[5]={0,1,-1,2,-2},Ans;
int n,a[N],fl[N],ok[N],fa[N],rd[N],l,first[N],F[N],flag[N];
struct E{int to,next;}e[N*2];
int go(int x,int y)
{
	x+=y;
	if (x<=0) x+=n;
	if (x>n) x-=n;
	return x+(y>0?0:n);
}
void link(int x,int y)
{
	e[++l]=(E){x,first[y]};first[y]=l;
}
void huan(int x)
{
	if (rd[x]!=0||flag[x]) return;
	flag[x]=1;rd[fa[x]]--;huan(fa[x]);
}
void dfs(int x,int y)
{
	fl[x]=y;
	if (fl[(x>n)?x-n:x+n]==y) ok[x]=1;
	for (int i=first[x];i;i=e[i].next)
		if (!fl[e[i].to])
			dfs(e[i].to,y);
	fl[x]=0;
}
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for (int i=1;i<=n;i++)
	{
		int y;
		y=go(i,LY[a[i]]);link(i,y);rd[y]++;fa[i]=y;
		y=go(i,-LY[a[i]]);link(i+n,y);rd[y]++;fa[i+n]=y;
	}
	for (int i=1;i<=n*2;i++)
		huan(i);
	for (int i=1;i<=n*2;i++)
		if (rd[i]) 
		{
			ok[i]=1;F[i]=i;rd[i]=0;
			for (int j=fa[i];j!=i;j=fa[j])
			{
				ok[j]=1;F[j]=i;rd[j]=0;
				for (int k=first[j];k;k=e[k].next)
					if (F[e[k].to]!=i) link(i,e[k].to);
			}
			fa[i]=0;
			dfs(i,i);
		}
	for (int i=1;i<=n;i++)
		if (!ok[i]&&!ok[i+n]) Ans++;
	printf("%d\n",Ans);
	for (int i=1;i<=n;i++)
		if (!ok[i]&&!ok[i+n]) printf("%d ",i);
}

看着同学都在刷线段树,TAT~~~
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值