Codeforces Round 934(div .1) A. MEX Game 1(博弈)

MEX Game 1

题面翻译

题目描述

Alice 和 Bob 在大小为 n n n 的数组 a a a 上玩一个游戏:Alice 有一个空数组 c c c 开始。两位玩家轮流进行游戏,Alice 先开始。

在 Alice 的回合中,她从 a a a 中选择一个元素,将该元素添加到 c c c 中,然后从 a a a 中删除该元素。

在 Bob 的回合中,他从 a a a 中选择一个元素,然后从 a a a 中删除该元素。

当数组 a a a 为空时游戏结束。游戏的得分定义为 c c c 的 MEX † ^\dagger 。Alice 希望最大化得分,而 Bob 希望最小化得分。找出如果两位玩家都采取最佳策略时的游戏最终得分。

† ^\dagger 整数数组的 MEX(最小排除数)定义为不在数组中出现的最小非负整数。例如:

例如:

  • [ 2 , 2 , 1 ] [2,2,1] [2,2,1] 的 MEX 是 0 0 0,因为 0 0 0 不属于数组。
  • [ 3 , 1 , 0 , 1 ] [3,1,0,1] [3,1,0,1] 的 MEX 是 2 2 2,因为 0 0 0 1 1 1 属于数组,但 2 2 2 不属于。
  • [ 0 , 3 , 1 , 2 ] [0,3,1,2] [0,3,1,2] 的 MEX 是 4 4 4,因为 0 0 0 1 1 1 2 2 2 3 3 3 属于数组,但 4 4 4 不属于。

输入格式

每个测试包含多个测试用例。第一行包含一个整数 t t t 1 ≤ t ≤ 2 ⋅ 1 0 4 1\leq t\leq2\cdot10^4 1t2104),表示测试用例的数量。接下来是测试用例的描述。

每个测试用例的第一行包含一个整数 n n n 1 ≤ n ≤ 2 ⋅ 1 0 5 1\le n\le2\cdot10^5 1n2105)。

每个测试用例的第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1,a2,,an 0 ≤ a i < n 0\le a_i<n 0ai<n)。

保证所有测试用例中 n n n 的总和不超过 2 ⋅ 1 0 5 2\cdot 10^5 2105

样例输入 #1

3
4
0 0 1 1
4
0 1 2 3
2
1 1

样例输出 #1

2
1
0

样例解释

在第一个测试用例中,得分为 2 2 2 的一个可能游戏如下:

  • Alice 选择元素 1 1 1。此时, a = [ 0 , 0 , 1 ] a=[0,0,1] a=[0,0,1] c = [ 1 ] c=[1] c=[1]
  • Bob 选择元素 0 0 0。此时, a = [ 0 , 1 ] a=[0,1] a=[0,1] c = [ 1 ] c=[1] c=[1]
  • Alice 选择元素 0 0 0。此时, a = [ 1 ] a=[1] a=[1] c = [ 1 , 0 ] c=[1,0] c=[1,0]
  • Bob 选择元素 1 1 1。此时, a = [ ] a=[] a=[] c = [ 1 , 0 ] c=[1,0] c=[1,0]
  • 最终, c = [ 1 , 0 ] c=[1,0] c=[1,0],其 MEX 为 2 2 2。请注意,这只是一个示例游戏,并不一定代表两位玩家的最佳策略。

这个问题仔细一想其实不算太难,想一想如果一个数出现两次以及两次以上的时候是不是爱丽丝百分之百能选到呢,答案是肯定的,就拿两个为例子,如果一个数字出现两次那么要么爱丽丝先拿那么就拿到了,要么鲍勃先拿,那么爱丽丝会紧跟其后把剩下的一个拿走。想一想如果一个数一次都没有出现过是不是爱丽丝一定拿不到,那么就剩下出现一次数字的情况了,从0遍历,排除出现两次以及以上的数字不看(因为不服怎么样一定能取到),第一次,这里用一个b数组存每个数的出现的个数,第一次出现b[i] = = 1,那么爱丽丝一定是先手拿,在这个基础上鲍勃如果足够聪明的话一定不会碰个数大于等于2的数,那么就是把的二个出现次数是1的给拿走,那么答案就是这个,即第二个出现 b[i] = =1 的下标,如果在第二个b[i] = =1之前出现了b[i] = = 0,那么下表就是答案。

下面展示一些 内联代码片

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int t ;
int n ;
int a[N];
int b[N];
int main() {
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> t;
	while (t --) {
		cin >> n;
		for(int i =1;i <= n;i ++)
		{
			cin >> a[i];
			b[a[i]] ++;
		}
		int cnt = 0,ans = 0;
		for(int i = 0;i <= n ;i ++)
		{
			if(b[i] == 0){
				ans = i;
				break;
			}
			if(b[i] == 1){
				cnt ++;
			}
			if(cnt == 2)
			{
				ans = i;
				break;
			}
			
		}
		for(int i = 0;i <= n;i ++)//我就算这样写也不想用memset,还有memset一般只能赋值为-1,0;不要瞎用,不然可以试一试,具体为神马可查查
		{
			b[i] = 0;
		}
		cout << ans << endl;
	}

	return 0;
}

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值