题解:P14359 [CSP-J 2025] 异或和 / xor(民间数据)

· · 题解

思路:

1. 前缀异或数组

定义前缀异或数组,其中 p_0 = 0p_i = a_1 \oplus a_2 \oplus \cdots \oplus a_i。\ 则区间 [l, r] 的异或和可表示为 p_r \oplus p_{l-1},当区间异或和等于 k 时,有 p_{l-1} = p_r \oplus k

2. 贪心选择策略

代码

#include <bits/stdc++.h>
using namespace std;

int n, k;
int p, last, counts;
// p:当前前缀异或值, last:最后选择的区间右端点, counts:选择的区间数量

int main() {
    scanf("%d %d", &n, &k);

    vector<int> a(n);
    for (int i = 0; i < n; i ++) cin >> a[i];

    unordered_map<int, vector<int> > Map;
    Map[0].push_back(0);

    for (int i = 1; i <= n; i ++) {
        p ^= a[i - 1]; // 更新前缀异或值
        int target = p ^ k;

         // 检查是否存在满足条件的前缀位置
        if (Map.find(target) != Map.end()) {
            vector<int>& pos = Map[target];

             // 二分查找第一个 >= last 的位置(确保区间不重叠)
            auto it = lower_bound(pos.begin(), pos.end(), last);
            // 如果找到合适的位置且该位置在当前位置之前
            if (it != pos.end() && *it < i) {
                counts ++;
                last = i;
            }
        }
        Map[p].push_back(i);
    }

    printf("%d\n", counts);
    return 0;
}