第十二届蓝桥杯Java省赛A组试题:异或数列

简介: 第十二届蓝桥杯Java省赛A组试题:异或数列

【题目描述】

初始时,Alice和Bob分别有一个整数a和b,有一个给定的长度为n的数列。a和b的初始值均为0。Alice和Bob轮流操作,Alice先手,每步可以从两个选项中选一种:

选项1:从数列中选一个X;给Alice的数异或上。

选项2:从数列中选一个X;给Bob的数异或上。

每个数Xi只能用一次,当每个数都被用过一遍后,游戏结束。拥有数大的一方获胜,双方数字相同即平局。

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


【输入格式】

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

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

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


【输出格式】

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

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


【样例输入】

4

1 1

1 0

2 2 1

7 992438 1006399 781139 985280 4729 872779 563580


【样例输出】

1

0

1

1


【评测用例规模与约定】

对于所有评测用例,1 ≤ T ≤ 200000,1 ≤ ∑Ti=1 ni ≤ 200000,0 ≤ Xi < 220。


【解题思路】

借鉴:该博客


首先明确,为什么给定一个数列,游戏的结局是确定的呢?

A赢的意思是:A能采取某种策略,不管B作何应对,A保证自己一定能赢;

B赢的意思是:B能采取某种策略,不管A作何应对,B保证自己一定能赢;

对于异或:0^X ——保持X ; 1^X——翻转X;

偶数次翻转将回到原来的状态,即与偶数个1异或将保持不变。


最后两个结果数A^B = a^b^sum ,其中sum为给定数列所有数的异或和,sum = X1^X2^...Xni,所以如果是平局(即A = B),则A^B=0(即 sum = 0)。


现在考虑sum != 0时,因为是按位异或,并且最后比较A和B两值的大小,所以要从二进制的最高位开始比较,如果最高位相等,比较次高位,以此往下比较,直到可以判断出结果。


用一个int型数组res[i]表示二进制的第i位上1的个数,如果某一位的res[i]为奇数,即该位上有奇数个1与a和b异或,比如有5个1,因为0不会改变状态,其(a,b)的状态转移过程一定是:(0,0)->翻转->平局->翻转->平局->翻转,也就是说在平局不管是(0,0)或(1,1)的基础上,Alice 和 Bob谁拥有最后一次翻转权(也就是最后一个1),谁就赢得游戏!


那怎么让最后一个1轮到自己身上?就要用到0了,因为0不会改变数的大小,但相当于让自己“轮空一次”。还是考虑上面5个1的情况:如果在最后一次翻转之前(不管在什么位置)插入偶数个0,则最后一次1的翻转权来到了先手 Alice,则先手胜出;如果在最后一次翻转之前(不管在什么位置)插入奇数个0,则最后一次1的翻转权来到了后手 Bob,则后手胜出。


因为Alice和Bob都“足够聪明”,面对奇数个1,Bob一定要去“ 抢0 ”,自己才有一线生机,而Alice也要以“ 抢0 ”来作应对,让最后一次翻转权回到自己手里,因为0的个数有限,最后决定胜负的就是0个数的奇偶性。


因此,如果某一位的res[i]为偶数,则游戏结果的这一位一定相等,考虑下一位 ;如果第i位上1的个数为 1,则一定是先手赢(输出:“1”);如果第i位上1的个数为大于1的奇数,0的个数为偶数,则先手赢(输出:“1”);如果第i位上1的个数为大于1的奇数,0的个数为奇数,则后手赢(输出:“-1”)。


Java代码:


import java.util.ArrayList;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        //该ArrayList用来暂存每次询问结果,待最后一次询问结束再统一输出
        ArrayList<Integer> res = new ArrayList<>();
        //n次询问
        for (int i = 0; i < n; i++) {
            int[] weis = new int[24]; //该数组用于存储二进制形式下每一位1的数量
            int m = scanner.nextInt();
            //长度为m的数列转为二进制并处理
            for (int j = 0; j < m; j++) {
                long l = scanner.nextLong();
                String string = Long.toBinaryString(l); //转为二进制
                String reStr = new StringBuilder(string).reverse().toString(); //反转,即高低位反转,便于存储与后面处理
                //判断二进制形式下每一位是否为1
                for (int k = 0; k < reStr.length(); k++) {
                    if (reStr.charAt(k) == '1') weis[k]++;
                }
            }
            //对每次询问后每一位中1的个数判断从而得到结果,并将结果先暂时存储在ArrayList-res中
            for (int j = weis.length - 1; j >= 0; j--) {
                if (weis[j] % 2 == 0 && j == 0) {
                    res.add(0);
                    break;
                }else if (weis[j] % 2 == 0){
                    continue;
                }
                if (weis[j] == 1){
                    res.add(1);
                    break;
                }else if (weis[j] % 2 == 1 && (m - weis[j]) % 2 == 0){
                    res.add(1);
                    break;
                }else if (weis[j] % 2 == 1 && (m - weis[j]) % 2 == 1){
                    res.add(-1);
                    break;
                }
            }
        }
        //输出结果
        for (int x : res){
            System.out.println(x);
        }
    }
}


相关文章
|
10月前
|
算法 Java C++
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
本文介绍了经典的0/1背包问题及其动态规划解法。
328 5
|
10月前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
435 6
|
人工智能 Python
蓝桥杯练习题(四):Python组之历届试题三十题
关于蓝桥杯Python组历届试题的三十个练习题的总结,包括题目描述、输入输出格式、样例输入输出以及部分题目的解题思路和代码实现。
416 0
蓝桥杯练习题(四):Python组之历届试题三十题
|
Java
2023届蓝桥杯大赛软件类国赛Java大学B组 互质 数论
2023届蓝桥杯大赛软件类国赛Java大学B组 互质 数论
172 1
|
存储 前端开发 算法
2016届蓝桥杯大赛软件类国赛Java大学B组 反幻方 暴力搜索
2016届蓝桥杯大赛软件类国赛Java大学B组 反幻方 暴力搜索
142 0
|
Java
2016届蓝桥杯大赛软件类国赛Java大学B组 愤怒小鸟 数学模拟
2016届蓝桥杯大赛软件类国赛Java大学B组 愤怒小鸟 数学模拟
156 4
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
142 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
160 1
|
2月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
136 0
下一篇
oss云网关配置