蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:位运算实战——二进制权限与最大异或解析

一、引言

进入十月下旬,青少儿编程赛事进入密集备考期:

  • 第十八届蓝桥杯软件赛 (C/C++ 程序设计、Python 程序设计均为核心科目)报名已于 2026-10-08 10:00 开启,至 2026-12-18 14:00 截止 ,省赛 / 全国选拔赛定于 2027 年 4 月,全国总决赛 2027 年 6 月中上旬。
  • 中国电子学会 2026 年 12 月青少年软件编程等级考试 (C/C++ 一级至十级、Python 一级至六级)报名 2026-09-23 --- 12-02 16:00,全国测试 12-10,统考 12-12(C/C++ 8:30--10:30、Python 14:00--15:00)。
  • 全国青少年信息素养大赛算法应用赛项,大纲明确包含二进制、位运算与基础算法。

三个赛事共同高频出现一个"看上去小、实际很能拉开差距"的知识点:位运算 。蓝桥杯填空题常考 lowbit、异或性质;电子学会考级把位运算列为独立章节;信息素养大赛的算法题也常借二进制优化。今天我们用一道原创题,把位运算从"记六个符号"打通到"01-Trie 最大异或"的完整能力链。

二、题目 / 项目目标

我们把位运算拆成两个递进的小项目,都来自"校园科技节"的真实化场景。

项目 A(基础):社团权限徽章

有 m 个用户,初始权限均为 0(二进制每一位代表一类权限)。随后有 q 次操作:

  • add u k:给用户 u 增加第 k 类权限(把第 k 位置成 1);
  • del u k:取消用户 u 的第 k 类权限(把第 k 位置成 0)。

所有操作结束后,输出:

  1. 拥有"管理员权限"(定义为第 30 位为 1)的用户数量;
  2. m 个整数,第 i 个为用户 i 权限中二进制 1 的个数(即其拥有的权限类别数)。

约束:m ≤ 1000,q ≤ 10^5,k ≤ 30。

项目 B(核心算法):异或谜题------最大异或数对

科技节颁奖台前挂着一串灯,编号为 a[1..n](均为非负整数)。主持人说:任选两盏不同的灯 ,把它们编号异或(XOR),能得到的最大结果是多少?

即:给定 n 个数 a[1..n],求 max(a[i] xor a[j])(i ≠ j)。

约束:n ≤ 2000,a[i] < 2^31。

三、核心考点

  1. 六种位运算符 :与 &、或 |、异或 ^、取反 ~、左移 <<、右移 >>。
  2. 置位 / 清位 / 取位:
  3. 置 1:x |= (1 << k)
  4. 清 0:x &= ~(1 << k)
  5. 取第 k 位:(x >> k) & 1
  6. 异或的三大性质:
  7. 自反性:a ^ a = 0,a ^ 0 = a;
  8. 交换律 / 结合律:a ^ b ^ c = a ^ (b ^ c);
  9. 可用于"出现奇数次的数""不进位加法"。
  10. 二进制位贪心 :要让 x xor y 尽量大,应从最高位开始,每一位尽量让结果为 1。
  11. 01-Trie(字典树) :把每个数的二进制位当作一条从高位到低位走出的路径存进 Trie,查询时贪心地走"相反位",即可在 O(log V) 内求出与 x 异或最大的数。

四、解法 / 拆解

项目 A:位运算直接建模

每个用户的权限就是一个整数,用上面三板斧即可,无需任何复杂结构。

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int m, q;
    if (!(cin >> m >> q)) return 0;
    vector<int> p(m, 0);
    const int ADMIN = 30;          // 管理员权限位
    while (q--) {
        string op; int u, k;
        cin >> op >> u >> k;
        if (op == "add")      p[u] |=  (1 << k);   // 置 1
        else if (op == "del") p[u] &= ~(1 << k);   // 清 0
    }
    int admin_cnt = 0;
    for (int x : p) if ((x >> ADMIN) & 1) ++admin_cnt;
    cout << admin_cnt << "\n";
    for (int i = 0; i < m; ++i) {
        if (i) cout << " ";
        // 统计 1 的个数:GCC 内置函数;其他编译器可手写(见进阶)
        cout << __builtin_popcount(p[i]);
    }
    cout << "\n";
    return 0;
}
python 复制代码
def main():
    import sys
    data = sys.stdin.read().split()
    if not data: return
    it = iter(data)
    m = int(next(it)); q = int(next(it))
    p = [0] * m
    ADMIN = 30
    for _ in range(q):
        op = next(it); u = int(next(it)); k = int(next(it))
        if op == "add":
            p[u] |= (1 << k)
        elif op == "del":
            p[u] &= ~(1 << k)
    admin_cnt = sum(1 for x in p if (x >> ADMIN) & 1)
    ones = [bin(x).count("1") for x in p]   # bin(x).count("1") 即 popcount
    print(admin_cnt)
    print(" ".join(map(str, ones)))

if __name__ == "__main__":
    main()

复杂度 :时间 O(q + m),空间 O(m),完全可过 q = 10^5。

项目 B 解法一:暴力枚举(入门 / 考级首选)

直接枚举所有 (i, j) 数对,取异或最大值。思路直白、零模板,适合电子学会考级与初期练习。

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n; if (!(cin >> n)) return 0;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    int ans = 0;
    for (int i = 0; i < n; ++i)
        for (int j = i + 1; j < n; ++j)
            ans = max(ans, a[i] ^ a[j]);
    cout << ans << "\n";
    return 0;
}
python 复制代码
import sys

def main():
    data = sys.stdin.read().split()
    if not data: return
    it = iter(data)
    n = int(next(it))
    a = [int(next(it)) for _ in range(n)]
    ans = 0
    for i in range(n):
        for j in range(i + 1, n):
            if a[i] ^ a[j] > ans:
                ans = a[i] ^ a[j]
    print(ans)

if __name__ == "__main__":
    main()

复杂度 :时间 O(n²),空间 O(n)。n ≤ 2000 时约 200 万次异或,完全够用。

项目 B 解法二:01-Trie 贪心(蓝桥杯 / 竞赛优化)

当 n 大到 10^5、数值到 2^31 时,O(n²) 会超时。把每个数的二进制(高位到低位,共 31 位)当作一条路径插入 Trie;查询 x 时,从最高位起,每一步都优先走与当前位相反的分支(这样该位异或就是 1),走不通才走相同位。

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int B = 30;   // 处理到 2^30 量级,共 31 位(0..30)

struct Node { int ch[2]; Node() { ch[0] = ch[1] = 0; } };
vector<Node> trie(1);                 // 0 号节点为根

void insert(int x) {
    int u = 0;
    for (int i = B; i >= 0; --i) {
        int b = (x >> i) & 1;
        if (!trie[u].ch[b]) {
            trie.push_back(Node());
            trie[u].ch[b] = trie.size() - 1;
        }
        u = trie[u].ch[b];
    }
}

int query(int x) {
    int u = 0, res = 0;
    for (int i = B; i >= 0; --i) {
        int b = (x >> i) & 1;
        int need = 1 - b;             // 希望走相反位,使该位异或为 1
        if (trie[u].ch[need]) { res |= (1 << i); u = trie[u].ch[need]; }
        else                    { u = trie[u].ch[b]; }
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n; if (!(cin >> n)) return 0;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    int ans = 0;
    for (int x : a) {
        // 先查询(只用已插入的数,避免 i==j),再插入自己
        if (trie[0].ch[0] || trie[0].ch[1]) ans = max(ans, query(x));
        insert(x);
    }
    cout << ans << "\n";
    return 0;
}
python 复制代码
class TrieNode:
    __slots__ = ("ch",)
    def __init__(self):
        self.ch = [None, None]   # ch[0], ch[1]

def insert(root, x, B=30):
    node = root
    for i in range(B, -1, -1):
        b = (x >> i) & 1
        if node.ch[b] is None:
            node.ch[b] = TrieNode()
        node = node.ch[b]

def query_max(root, x, B=30):
    node, res = root, 0
    for i in range(B, -1, -1):
        b = (x >> i) & 1
        need = 1 - b
        if node.ch[need] is not None:
            res |= (1 << i)
            node = node.ch[need]
        else:
            node = node.ch[b]
    return res

def max_xor_trie(a, B=30):
    root = TrieNode()
    ans = 0
    for x in a:
        # 先查询(只用已插入的数),再插入自己
        if root.ch[0] is not None or root.ch[1] is not None:
            cand = query_max(root, x, B)
            if cand > ans: ans = cand
        insert(root, x, B)
    return ans

if __name__ == "__main__":
    import sys
    data = sys.stdin.read().split()
    if data:
        it = iter(data); n = int(next(it))
        a = [int(next(it)) for _ in range(n)]
        print(max_xor_trie(a))

复杂度 :插入 / 查询各 O(B),B = 31,总时间 O(n·B)、空间 O(n·B),n = 10^5 也轻松通过。

五、时间 / 空间复杂度小结

项目 解法 时间 空间
A 权限徽章 位运算 O(q + m) O(m)
B 最大异或 暴力枚举 O(n²) O(n)
B 最大异或 01-Trie O(n·B) O(n·B)

六、易错点(七条,考试常踩)

  1. 运算符优先级 :&、|、^ 的优先级低于 ==、<、+。写 if ((x >> k) & 1 == 1) 会先算 1 == 1 再 &,必须加括号 :if (((x >> k) & 1) == 1)。
  2. &= / |= 与 = 混用 :清位要用 x &= ~(1 << k),漏掉 & 写成 x = ~ (1 << k) 会把其它位全清掉。
  3. 移位越界溢出 :1 << k 在 C++ 中是 int,当 k ≥ 31 时左移溢出为 0 或负数。位宽可能到 31 位时,请写成 1LL << k(用 long long 存权限)。
  4. 取反 ~ 的符号 :~x 在 C++ 里是按补码取反(含符号位),所以"清某位"要配合 &,不要单独用 ~x 当"取反整个数"。
  5. popcount 的坑 :手写好 while (x) { cnt += x & 1; x >>= 1; } 时,若 x 是有符号负数会死循环;权限用非负整数即可,或先转无符号。
  6. 异或查询前要先插入还是先查询 :01-Trie 求"两不同数异或最大"时,必须先 query 再 insert 自己,否则会和自己异或得到 0,且漏掉"和之前的数配对"的情况。
  7. Trie 必须对齐到固定高位 :插入 / 查询都要从同一个最高位 B 开始逐位走,不能因为"这个数很小"就少走几位,否则不同长度的数会在错误的层面对齐,答案错误。

七、进阶

  1. lowbit 与树状数组 :lowbit(x) = x & (-x) 取出最低位的 1,是树状数组(Fenwick Tree)的基石;蓝桥杯 / 考级中"统计逆序对""单点改区间查"常与之配合。
  2. 状态压缩枚举子集 :n ≤ 20 时,用 1<<n 个整数表示"选 / 不选每个元素"的所有组合,for (int s = 0; s < (1<<n); ++s) 即可遍历全部子集;还可 for (int sub = s; sub; sub = (sub-1) & s) 枚举 s 的所有子集,是蓝桥杯经典技巧。
  3. 01-Trie 不止最大异或:把"任意两数异或最大值"升级为"区间内两数异或最大值"(可持久化 Trie),或"异或某个定值 k 后最大"(同样走相反位)。
  4. 异或找"出现奇数次的数" :a[1] ^ a[2] ^ ... ^ a[n],利用 x ^ x = 0 把所有成对出现的数消掉,只剩出现奇数次的那个;若只有一个数出现一次、其余都两次,结果是它就是它本身。
  5. 位运算加速小技巧 :判断奇偶用 x & 1 比 x % 2 快;取模 2 的幂用 x & ((1<<k)-1) 代替 x % (1<<k);交换两数可用 a ^= b; b ^= a; a ^= b;(注意 a、b 不能是同一变量,否则变 0)。

八、小结与互动

位运算不是"背六个符号",而是把问题搬到二进制层面重新观察:权限用一位表示、异或当成不进位加法、Trie 把"找最大异或"变成"高位贪心走相反路"。它是蓝桥杯填空题、电子学会考级独立章节、信息素养大赛算法题共同的高频考点,性价比极高。

今日互动 :你在做题时还踩过哪些位运算的坑?是优先级漏括号,还是 1 << 31 溢出?欢迎在评论区留言,下一篇我们可以专门拆解"状态压缩 DP 入门"。

(本文为原创练习题,非任何赛事真题原题;代码均在 C++ / Python 双环境下可运行。)


📚 免费少儿编程资料(夸克网盘领取)

以下资料来自夸克网盘分享,点击链接可直接保存;若需在 App 内打开,也可复制下方明文链接:

  1. 全国青少年信息素养大赛复赛集训题目Python&C++.docx
    https://pan.quark.cn/s/93995d3cb150
  2. 2024信息素养-智能算法应用挑战赛-复赛初中组题目7月7日.pdf
    https://pan.quark.cn/s/da97b5dbf75d
  3. Python背记手册.pdf
    https://pan.quark.cn/s/7568ae9ca92b
  4. Python课程
    https://pan.quark.cn/s/a94bf02d00c6
  5. 2024信息素养大赛图形化复赛集训题答案3-9
    https://pan.quark.cn/s/6ccab7ec3cbc
  6. 2025年03月份电子学会考级真题
    https://pan.quark.cn/s/4403c4228912
  7. 2025全国青少年信息素养大赛赛项说明
    https://pan.quark.cn/s/d9d0df4a9f29
  8. 青少儿信息素养大赛编程资料
    https://pan.quark.cn/s/4ab6bd83be8a

资料持续更新,关注获取最新分享。

相关推荐
在世修行1 小时前
智学文枢:理科分析引擎
python·ai·pyside·理科教学
广州智造1 小时前
Radioss中破坏模型FAILTAB1的详细介绍
数据库·人工智能·算法·机器学习·仿真软件·radioss
青少儿编程课堂1 小时前
2026蓝桥杯青少组图形化真题:校园飞机大战解析(全国青少年信息素养·电子学会图形化考级)
c++·python·算法·bfs·信息学竞赛
开开心心就好1 小时前
证件照排版打印工具,免费可自定义尺寸
服务器·开发语言·算法·随机森林·pdf·音视频·散列表
lisw051 小时前
导数与机器学习优化!
算法·机器学习·数学建模
方知我1 小时前
01FastAPI基础入门
人工智能·python
CodeYp20191 小时前
第16讲:set 和 map 的使用
开发语言·c++·set·map
海绵宝宝转agent2 小时前
leetcodehot100个人题解
java·笔记·学习·算法
傲世仙尊2 小时前
vector起步与底层-三个指针迭代器失效与为模板升级内置类型
c++