【题解】Luogu P8743 【[蓝桥杯 2021 省 A] 异或数列】

最近刚好在刷博弈论,看到这道题没有题解,所以刚好来水一发

题目链接

[蓝桥杯 2021 省 A] 异或数列

题目描述

Alice 和 Bob 正在玩一个异或数列的游戏。初始时,Alice 和 Bob 分别有一 个整数 ab, 有一个给定的长度为 n 的公共数列 X1,X2,,Xn

Alice 和 Bob 轮流操作,Alice 先手,每步可以在以下两种选项中选一种:

选项 1: 从数列中选一个 Xi 给 Alice 的数异或上, 或者说令 a 变为 aXi 。(其中 表示按位异或)

选项 2: 从数列中选一个 Xi 给 Bob 的数异或上,或者说令 b 变为 bXi

每个数 Xi 都只能用一次, 当所有 Xi 均被使用后(n 轮后)游戏结束。游戏结束时, 拥有的数比较大的一方获胜,如果双方数值相同,即为平手。

现在双方都足够聪明,都采用最优策略,请问谁能获胜?

输入格式

每个评测用例包含多组询问。询问之间彼此独立。

输入的第一行包含一个整数 T,表示询问数。

接下来 T 行每行包含一组询问。其中第 i 行的第一个整数 ni 表示数列长度,随后 ni 个整数 X1,X2,,Xni 表示数列中的每个数。

输出格式

输出 T 行,依次对应每组询问的答案。

每行包含一个整数 101 分别表示 Alice 胜、平局或败。

样例 #1

样例输入 #1

4
1 1
1 0
2 2 1
7 992438 1006399 781139 985280 4729 872779 563580

样例输出 #1

1
0
1
1

提示

对于所有评测用例, 1T2×105,1i=1Tni2×105,0Xi<220

蓝桥杯 2021 第一轮省赛 A 组 G 题。

题目解释

  • 读完了之后发现完全没说a和b是什么东西,看完样例发现,a和b默认应该为0

性质

  • 可以看到,双方的选择最终一定会把所有的数字选择光,而且根据异或的性质,异或之后得到的结果和数字的异或顺序无关,所以我们最后得到的Alice和Bob的数字AB一定满足:
    • AB=X1X2...Xn
  • 可以看出,假如将所有Xi进行二进制拆分,并且统计每一位的1的个数,设这个统计数组为ans,那么Alice和Bob的策略就是抢ans的最高位的1
    • 如果ans最高位的1的个数为1个,那么一定是先手必胜。因为只要Alice先手抢到了这个贡献了1的这个数字,(也就是最大的数字),那么剩下的过程无论Alice和Bob如何选,无论异或在A或者B上,最高位的这个1都是无法被抵消掉的,在最终的A中都有最高位的这个1,而B的同一位为0,所以A一定大于B
    • 如果最高位的1的个数为奇数个(非1个),那么显然在Alice选择了一个高位1之后,他们谁都不会优先去选择能为最高位贡献1的数字了,因为此时能为最高位贡献1的数字剩余一定是偶数个,如果Bob先选了某一个高位1和B/A异或,那么Alice一定会选择一个高位1去跟B/A异或,来抵消掉刚刚Bob的操作对于最高位的影响。对于Alice也是如此。
      • 所以此时两人一定都会开始选择一些“无关紧要”的数字,直到某一方不得不选择对于最高位有影响的数字
      • 所以此时:如果n为偶数,那么后手赢
      • 如果n为奇数,那么先手赢
    • 如果最高位的1的个数为偶数个,那么一方选择了某一个为最高位贡献了一个1的数字时,另一方一定会紧随其后选择另一个也为最高位贡献了一个1的数字,这样使得在AB中的这一位抵消掉,否则会让自己陷入劣势,所以我们应该看次高位,如果仍为偶数则看次次高位,直到某一个位的“1的个数”是奇数为止。

代码

#include<bits/stdc++.h>
#define re register
#define ll long long
#define inc(i,j,k) for(re int i=j;i<=k;i++)
#define dec(i,j,k) for(re int i=j;i>=k;i--)
using namespace std;
const int maxn = 2e5+10;
inline int read(){
	re int x=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+(ch^48); ch=getchar();}
	return x*f;
}
inline ll re_ad(){
	re ll x=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+(ch^48); ch=getchar();}
	return x*f;
}
int T,n;
ll a[maxn];
int bit[32],highbit;
int cnt;
inline void div(ll x){
	cnt=1;
	while(x){
		if(x&1) bit[cnt]++;
		cnt++;
		x>>=1;
	}
	highbit = max(highbit,cnt);
}
int main(){
	T=read();
	inc(t,1,T){
		n=read();
		memset(bit,0,sizeof(bit));
		highbit=0;
		ll check = 0;
		inc(i,1,n){
			a[i]=re_ad();
			check^=a[i];
			div(a[i]);
		}
		if(!check){
			puts("0");
		}else{
			dec(i,highbit,1){
				if(bit[i]&1){
					if(bit[i]==1) puts("1");
					else if(n&1) puts("1");
					else puts("-1");
					break;
				}
			}
		}
	}
}
/*
1
5 4 2 8 7 3
*/

posted @   ZzTzZ  阅读(126)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示