#C241123C. 旁观者


#C241123C. 旁观者

标签(Label)

  • 博弈论

网址(Website)

题目详情 - 旁观者 - Super

题解 - 旁观者 - Super

题目(Problem)

输入数据 1

1 3
2
1
1 0
5
1 2 2 1
0 0 0 1 0
8
1 2 2 2 1 6 1
1 0 0 0 1 0 1 0

输出数据 1

yes
no
yes

【样例1解释】

在第一轮游戏中最后一个取得棋子一定是第 $2$ 个,所以小 $\text{C}$ 一定胜。

在第二轮游戏中小 $\text{C}$ 先取了 $1$ 号棋子,大 $\text{C}$ 如果取 $5$ 号棋子,那么小 $\text{C}$ 就只能取 $2$ 号棋子,大 $\text{C}$ 此时取 $3$ 号棋子,那么小 $\text{C}$ 就只能取 $4$ 号棋子,这样小 $\text{C}$ 就输了。

【样例2】

见选手目录下的 $bystander/bystander2.in$ 与 $bystander/bystander2.ans$。

该样例数据满足测试点 $5\sim7$ 的限制。

【样例3】

见选手目录下的 $bystander/bystander3.in$ 与 $bystander/bystander3.ans$。

该样例数据满足测试点 $8\sim10$ 的限制。

【样例4】

见选手目录下的 $bystander/bystander4.in$ 与 $bystander/bystander4.ans$。

该样例数据满足测试点 $11\sim14$ 的限制。

【样例5】

见选手目录下的 $bystander/bystander5.in$ 与 $bystander/bystander5.ans$。

该样例数据满足测试点 $15\sim18$ 的限制。

【样例6】

见选手目录下的 $bystander/bystander6.in$ 与 $bystander/bystander6.ans$。

该样例数据满足测试点 $19\sim20$ 的限制。

题解(Solution)

容易发现依赖关系构成了一棵树。

考虑最优操作时小 $\text{C}$ 和大 $\text{C}$ 会怎么取棋子,很明显,二人一定会贪心去取棋子,而且肯定是想尽量把对方的颜色的棋子取完,这样最后剩下的就是自己胜利的颜色。

那么对于 $p_i=1$ 的点,我们就想到了答案。接下来考虑将这个思想拓展成一棵正常的树的形式。容易发现父亲的颜色一定不影响最后的答案。考虑如果一些点有一个父亲,谁会更希望去多花一步取掉这个父亲呢?如果这些点白子和黑子数量不同,那么黑的多小 $\text{C}$ 肯定更希望删掉这个点,白的多大 $\text{C}$ 肯定更希望删掉这个点,一样多的时候两个人只能轮流删,那么删到最后的人就输了,具体来讲,如果 $n$ 为奇数,小 $\text{C}$ 最后删完的一定是黑子,那么小 $\text{C}$ 输,否则大 $\text{C}$ 就输了。

考虑使用 $f_i$ 表示以 $i$ 为子树时白子和黑子数量之差(白子为正),那么当 $f_i>0$ 的时候,大 $\text{C}$ 更希望删掉这个节点来解锁后面的节点,因此他会多花一步,那么相当于多了一个白子,则 $f_i\leftarrow f_i+1$ ;如果 $f_i<0$ ,同样的道理,有 $f_i\leftarrow f_i-1$ ,否则,根据 $n$ 的奇偶性判断,因为白色的和黑色的相等,如果 $n$ 为奇数,那么最后拿走父节点的一定是在奇数次行动的小 $\text{C}$ ,因此 $f_i\leftarrow f_i-1$ ,否则就是在偶数次行动的大 $\text{C}$ ,有 $f_i\leftarrow f_i+1$ 。

最后只需要判断 $f_i$ 大于 $0$ 还是小于 $0$ 就好了,特别的,容易发现如果 $f_i=0$ ,由于是小 $\text{C}$ 先走,所以最后一定是大 $\text{C}$ 取走黑色棋子,还是小 $\text{C}$ 输。

时间复杂度:$O(\sum n)$ 。

出题者题解

代码(Code)

15分
#include<bits/stdc++.h>
#include<vector>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
#define show(a) For(i,1,n) cerr<<a[i]<<' ';cerr<<'\n'
using namespace std;
#define P pair<int,int> 
#define int long long
#define x first
#define y second
#define in(x,l,r) (l<=x && x<=r)
inline int rd(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}template<typename G>
void write(G x){
	if(x<0) putchar('-'),write(-x);
	else if(x<=9) putchar('0'+x);
	else write(x/10),putchar('0'+x%10);
}constexpr int inf = 0x3f3f3f3f3f3f3f3f;
constexpr int N = 1012345;
bool ST;int tid,Tt;

vector<int> ft[N];
int n,c[N];

namespace Q{
	void Solve1(){
		int s1=0, s2=0;
		For(i,2,n){
			s1 += c[i]==0;
			s2 += c[i]==1; 
		}printf("%s\n", (s1>s2) ? "yes" : "no");
	}
}

void Solve(){
	For(i,1,n) ft[i].clear();
	
	n=rd();For(x,2,n){
		int y=rd();
		ft[x].emplace_back(y);
		ft[y].emplace_back(x);
	}For(i,1,n) c[i]=rd();
	
	if(in(tid,5,7)) return Q::Solve1();
}

bool ED;
signed main(){
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	freopen("bystander.in","r",stdin);
	freopen("bystander.out","w",stdout);
	tid=rd();Tt=rd();double Tim=clock();
	while(Tt--) Solve();
	return cerr<<"TIME:"<<(clock()-Tim)/CLOCKS_PER_SEC,0;
}
100分
#include<bits/stdc++.h>
#include<vector>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
#define show(a) For(i,1,n) cerr<<a[i]<<' ';cerr<<'\n'
using namespace std;
#define P pair<int,int> 
#define int long long
#define x first
#define y second
#define in(x,l,r) (l<=x && x<=r)
inline int rd(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}template<typename G>
void write(G x){
	if(x<0) putchar('-'),write(-x);
	else if(x<=9) putchar('0'+x);
	else write(x/10),putchar('0'+x%10);
}constexpr int inf = 0x3f3f3f3f3f3f3f3f;
constexpr int N = 1012345;
bool ST;int tid,Tt;

vector<int> ft[N];
int n,c[N],f[N];

void dfs(int x){
	if(ft[x].empty()) return f[x]=c[x]?-1:1, void();
	f[x] = 0;
	for(auto y:ft[x]) dfs(y), f[x] += f[y];
	if(f[x] > 0) f[x]++;
	else if(f[x] < 0) f[x]--;
	else f[x] += n&1?-1:1;
}

void Solve(){
	n=rd();For(i,1,n) ft[i].clear();
	For(x,2,n) ft[rd()].emplace_back(x);
	For(i,1,n) c[i]=rd();
    dfs(1);
	if(f[1]>0) puts("yes");
	else puts("no");
}

bool ED;
signed main(){
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	freopen("bystander.in","r",stdin);
	freopen("bystander.out","w",stdout);
	tid=rd();Tt=rd();double Tim=clock();
	while(Tt--) Solve();
	return cerr<<"TIME:"<<(clock()-Tim)/CLOCKS_PER_SEC,0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录