IOI2017 Day1 Toy Train 题解

传送门

题解

这题思维难度比较大_

首先,对任意集合 S S ,定义函数 f A ( S ) f_A(S) 为不管B怎样A都能进入 S S 的起点的集合, f B ( S ) f_B(S) 同理

设充电站集合为 R R ,则如果起点在 f A ( R ) f_A(R) 以外B必胜(即B一定有一种策略使得火车无法进入 R R

如果 f A ( R ) f_A(R) 为全集则A赢(不管怎样A总能使火车进入 R R

如果 f A ( R ) f_A(R) 不为全集,设 X X f A ( R ) f_A(R) 的补集,则如果起点属于 X X 则B必胜

如果起点属于 f B ( X ) f_B(X)​ 中B一定可以进入 X X​ ,所以B同样必胜

剩下的节点胜负未定,我们可以抠掉这些B胜的节点,继续判断 f A ( R ) f_A(R) 是否为全集并重复上述过程,直到 f A ( R ) f_A(R) 为全集为止,此时剩下的节点就是A必胜的起点


现在问题就是快速求 f A f_A f B f_B (由于求 f A f_A 的过程和求 f B f_B 的过程相似,所以这里只讨论求 f A f_A 的方法)

由于 n 5000 n\le 5000 ,所以可以根据定义直接求 f A f_A

首先 f A ( S ) f_A(S) 至少是 S S

每次选一个点,它进入 f A f_A 的条件是:

  • 它由A掌控,并且它至少有一条道路通向 S S
  • 它由B掌控,并且它所有道路全部都通向 S S

具体实现时可以每次在 S S 中取出一个尚未取出的节点,并更新每个点是否满足条件。

举个栗子

1.png

红色节点属于A,蓝色节点属于B,黄色标记代表这是一个充电车站

首先 R = { 2 , 9 } R=\lbrace2,9\rbrace

按照前面的方法求出 f A ( R ) = { 2 , 3 , 4 , 5 , 9 } f_A(R)=\lbrace2,3,4,5,9\rbrace

X = n o t f A ( R ) = { 1 , 6 , 7 , 8 } X=notf_A(R)=\lbrace1,6,7,8\rbrace

f B ( X ) = { 1 , 2 , 6 , 7 , 8 } f_B(X)=\lbrace1,2,6,7,8\rbrace

{ 1 , 2 , 6 , 7 , 8 } \lbrace1,2,6,7,8\rbrace 抠掉,得到 { 3 , 4 , 5 , 9 } \lbrace3,4,5,9\rbrace

2.png

用类似的方法,得 R = { 9 } R=\lbrace9\rbrace f A ( R ) = { 3 , 4 , 5 , 9 } f_A(R)=\lbrace3,4,5,9\rbrace 为全集

所以得到答案 w = { 0 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 1 } w=\lbrace0,0,1,1,1,0,0,0,1\rbrace​

我在交的时候忘删了调试语句,结果调了好久…qwq

#include<bits/stdc++.h>
using namespace std;
const int N=5005;
int n,m,q[N],h,t,vis[N];
vector<int> e[N],e2[N];
vector<int> f(int flag,vector<int> a,vector<int> r,vector<int> res){
	memset(vis,0,sizeof(vis));
	vector<int> ans(n),deg(n);
	t=0,h=-1;
	for(int i=0;i<n;i++)if(r[i]&&res[i])q[++h]=i,ans[i]=1;
	for(int i=0;i<n;i++){for(int j=0;j<(int)e[i].size();j++)if(res[e[i][j]]){if(a[i]^flag)deg[i]++;else deg[i]=1;}}
	while(t<=h){
		int v=q[t++];
		for(int i=0;i<(int)e2[v].size();i++){
			int u=e2[v][i];
			if(!ans[u]&&res[u]){deg[u]--;if(!deg[u])ans[q[++h]=u]=1;}
		}
	}
	return ans;
}
vector<int> who_wins(vector<int> a,vector<int> r,vector<int> u,vector<int> v){
	n=a.size(),m=u.size();
	while(m--)e[u[m]].push_back(v[m]),e2[v[m]].push_back(u[m]);
	vector<int> ans(n);
	for(int i=0;i<n;i++)ans[i]=1;
	while(1){
		int flag=1;
		vector<int> res1=f(1,a,r,ans);
		for(int i=0;i<n;i++)if(ans[i]&&!res1[i])flag=0;
		if(flag)return ans;
		for(int i=0;i<n;i++)res1[i]^=1;
		vector<int> res2=f(0,a,res1,ans);
		for(int i=0;i<n;i++)if(res2[i])ans[i]=0;
	}
	return ans;
}

猜你喜欢

转载自blog.csdn.net/qq_27327327/article/details/80711824