异或数列 蓝桥杯2021

//
// Created by 86199 on 2022/3/30.
//

//异或数列
//alice和bob最初分别拥有两个数值相同的数,有一个固定大小的数列X[],
//两人分为先手后手从中选择任意位置上的数Xi与自己的数或者对方的数进行异或,每个位置上的数只能用一次,
//直到X数列中的元素全部用完,数值大的一方获胜,alice胜:1,平手:0,alice负:-1。

/*
 * 分析:
 * alice可进行的操作有(bob同样):
 * 1 选择一个数对自己当前的数进行异或,使自己当前的数变大
 * 2 选择一个数对bob的数进行异或,使bob当前的数变小
 * 3 alice会怎么选择?由于是最优选择,所以alice肯定会做出操作后与初始值的差值最大的选择
 *
 * 特殊情况:
 * 1 数列中所有数进行异或后结果为0;
 * 导致这种情况有两种情形:
 * 1 数列大小为偶数,且数列中每一个数值的个数为两个,也就是说,数列中数值不同的数的个数为n/2
 * 2 数列大小为奇数,最大偶数个数的情况符合1情形,且多出来的一个奇数为0
 *
 * 对于特殊情况:
 * 如果数列大小为偶数,alice先手选择对自己造成优势最大的数进行异或,或者选择对bob造成劣势最大的数进行异或,
 * 但无论哪种选择,当bob进行后手操作时,都可以选择同样的数进行同样操作,因此当数列全部选完后,alice和bob的数的大小都没有变,平手
 * 如果数列大小为奇数,alice和bob做出和以上的同样的操作,多出来的一个数为0,alice先手操作,任何数与0异或等于本身,平手
 * 因此,当数列的所有数累计异或后结果为0,对弈结果必然为平手
 *
 * 对于普遍情况:
 * 判定规则:如果数列累计异或结果不为0,那么在进行所有异或操作后,结果所对应的二进制数1的位数最高的人获胜
 * 如果将数列中每一个数所对应的二进制数中为1的位进行累加,有以下几种情况:
 * 1 统计所得最高位为1的数的个数只有一个,由于alice是先手,选择这个数对自己或bob操作,后续所有数的这一位都是0,任何数与0异或都等于本身,alice必胜
 * 2 统计所得最高位为1的数的个数为偶数个,alice和bob各选一半对自己或对方进行操作,对于这一位的最终结果alice和bob最终为平手,继续对次一位重复判断,不用进行任何操作
 * 3 统计所得最高位为1的数的个数为奇数个,有两种情况:
 *      ① 数列大小为奇数,那么这一位为0的数的个数为偶数,如果alice和bob都选择先将最高位为1的数选完,alice先手,最后一个高位为1的数属于alice,alice胜;
 *         如果alice先选高位1的数,bob选0,alice也为了拿到最后一个高位数跟着选0,由于为0的个数为偶数,bob先选所以bob先选完,不得不开始选高位为1的数,
 *         由于开始已经拿了一个,这时候高位1的个数为偶数,最后一个属于alice,alice胜;
 *         也就是说,这种情况下,只要alice先选高位1,无论bob先选高位1还是高位0都必输
 *         由于alice会做出最优决策,所以alice必胜;
 *
 *      ② 数列大小为偶数,那么这一位为0的数的个数为奇数,alice先手,如果alice先选高位1,为了确保能拿到最后一个高位1,bob不会跟着选,而是先选高位0,
 *         alice不可能继续选高位去创造bob的优势或者减小自己的优势,只能跟着选高位0,结果最后一个高位0必属于bob,alice只能选高位1,bob胜
 *         如果alice先选高位0,bob选高位1,alice接下来不可能选高位1,只能将高位0选完,最后一个属于bob,alice只能选高位1,bob胜
 *         也就是说,这种情况下,只要bob第一次后手先选0,无论alice先手选的高位1还是高位0都必输
 *         由于bob会做出最优决策,所以bob必胜*/

#include <iostream>
#include <bits/stdc++.h>

using namespace std;

void bitCount(int *res, int bit[], int length);

void gamingRes(int res, const int *bit, int length, int n);

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        int length;
        cin >> length;
        int res = 0;
        int *bit = new int[22];
        memset(bit, 0, sizeof(*bit));
        bitCount(&res, bit, length);
        gamingRes(res, bit, 20, length);
    }
    return 0;
}

void bitCount(int *res, int bit[], int length) {
    for (int j = 0; j < length; j++) {
        int x;
        cin >> x;
        *res ^= x;
        int index = 1;
        while (x > 0) {
            if ((x & 1) > 0) {
                bit[index]++;
            }
            x >>= 1;
            index++;
        }
    }
}

void gamingRes(int res, const int *bit, int length, int n) {
    if (res == 0) {
        cout << 0 << endl;
    } else {
        for (int i = length; i > 0; i--) {
            if (bit[i] == 1) {
                cout << 1 << endl;
                break;
            }
            if ((bit[i] & 1) == 1) {
                if ((n & 1) == 1) {
                    cout << 1 << endl;
                    break;
                } else {
                    cout << -1 << endl;
                    break;
                }
            }
        }
    }
}
<think>嗯,用户想了解蓝桥杯中与异或相关的题目解法或知识,特别是解题思路。首先,我需要回忆一下蓝桥杯常见的异或题目类型,以及相关的解题方法。根据提供的引用内容,有几个例子,比如异或数列、选数异或异或变换等。这些题目可能涉及到异或的基本性质,比如交换律、结合律,以及异或的特殊情况,比如相同数异或结果为0,不同为1。 首先,我应该从异或的基础知识开始整理,确保用户理解异或的基本性质。然后结合具体的题目例子,比如引用中的异或数列,分析如何统计二进制位上1的出现次数,从而判断最高位的胜负情况。这可能需要分情况讨论,比如当某一位的1出现奇数次时,先手可能有优势。 接下来,选数异或的问题可能需要使用动态规划或者前缀异或数组来处理区间查询,判断是否存在两个数的异或等于目标值。这里需要想到异或的性质,如果a ^ b = x,那么a ^ x = b,所以可以记录之前出现过的数,快速查找是否存在对应的b。 还有异或变换的问题,引用4中提到变换后的结果可能具有周期性,可能需要找到规律或者循环节,避免重复计算。比如,通过观察变换后的结果,发现周期性后可以快速计算多次变换后的结果。 此外,用户可能需要了解如何将问题转化为异或操作,例如位运算的统计、前缀异或数组的应用、动态规划等技巧。同时,要注意蓝桥杯题目的数据范围,选择合适的算法,避免超时。 在整理过程中,需要确保所有数学表达式符合用户提供的格式要求,行内用$...$,独立公式用$$...$$,并且正确引用提供的参考资料。例如,在解释异或数列的解题思路时,引用2中的分析,说明统计每位1的出现次数是关键。 还要考虑用户可能的疑问,比如如何处理异或的位运算特性,如何高效统计二进制位,或者如何优化算法以应对大数据量。可能需要举例说明,比如用cnt数组记录每一位1的个数,然后从高位到低位判断胜负条件。 最后,生成的相关问题要围绕异或题目展开,例如异或数列的具体步骤、选数异或的动态规划实现、异或变换的周期性分析等,帮助用户进一步深入学习。</think>### 蓝桥杯异或运算题目解题思路 #### 1. 异或运算基础知识 异或运算(XOR)满足以下性质: - 交换律:$a \oplus b = b \oplus a$ - 结合律:$(a \oplus b) \oplus c = a \oplus (b \oplus c)$ - 自反性:$a \oplus a = 0$,$a \oplus 0 = a$ - 若$a \oplus b = c$,则$c \oplus b = a$,$c \oplus a = b$ #### 2. 常见题型及解法 **题型1:异或数列(如引用[2])** - **问题描述**:Alice和Bob轮流选择数列中的数进行异或,最终值大者获胜。 - **解题思路**: 1. 计算所有数的异或和$sum = x_1 \oplus x_2 \oplus \dots \oplus x_n$。若$sum=0$则为平局。 2. 统计每个二进制位上1的出现次数$cnt_i$。 3. **从最高位开始判断**: - 若某位$cnt_i$为奇数,则先手必能获得该位的1,从而获胜。 - 若该位$cnt_i$为偶数,则双方可互相抵消,继续判断低位[^2]。 **题型2:选数异或(如引用[3])** - **问题描述**:在区间$[L, R]$内判断是否存在两个数$a, b$满足$a \oplus b = x$。 - **解题思路**: 1. 利用**前缀异或数组**或**哈希表**预处理: - 遍历数组时记录每个数及其索引。 - 若当前数为$a$,检查$a \oplus x$是否已存在。 2. 对于多次查询,可用动态规划预处理每个位置$i$对应的最近合法左边界$dp[i]$,查询时判断$dp[R] \geq L$是否成立[^3]。 **题型3:异或变换(如引用[4])** - **问题描述**:二进制串经过多次变换,每次每个位置变为前一位与当前位的异或值。 - **解题思路**: 1. 观察变换规律,**寻找周期性**。例如初始值10110经变换后呈现周期特性。 2. 若变换次数$t$超过周期长度,则取模运算减少计算量[^4]。 #### 3. 实战技巧 - **位统计法**:将问题拆解到二进制每一位,统计1的出现次数(如异或数列)。 - **前缀异或**:利用前缀异或数组快速计算区间异或值。 - **哈希优化**:通过哈希表存储历史异或值,降低时间复杂度。 ```python # 选数异或问题的哈希表解法示例 def find_xor_pair(arr, x): seen = {} for num in arr: if num ^ x in seen: return True seen[num] = True return False ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值