2 条题解

  • 1
    @ 2026-3-14 15:59:49

    思路分析

    首先考虑一个朴素做法:

    • 枚举所有区间 [l,r][l,r]
    • 计算区间异或和

    时间复杂度是 O(n2)O(n^2),当 n=105n=10^5 时显然会超时(约 101010^{10} 次操作)。

    前缀异或优化

    我们定义前缀异或和数组:

    b[i]=a[1]a[2]a[i]b[i] = a[1] \oplus a[2] \oplus \cdots \oplus a[i]

    那么区间 [l,r][l,r] 的异或和为:

    b[r]b[l1]b[r] \oplus b[l-1]

    转化问题

    要求:

    b[r]b[l1]=xb[r] \oplus b[l-1] = x

    等价于:

    b[l1]=b[r]xb[l-1] = b[r] \oplus x

    核心思想

    在遍历到 rr 时:

    • 只需要统计之前有多少个满足 b[l1]=b[r]xb[l-1] = b[r] \oplus x
    • 用一个哈希表记录前缀异或和出现次数

    特殊情况处理

    当:

    b[r]x=0b[r] \oplus x = 0

    即:

    b[r]=xb[r] = x

    说明区间 [1,r][1,r] 本身就是一个合法区间。

    为了统一处理这种情况,需要:

    cnt[0] = 1;
    

    表示“空前缀”出现过一次。

    算法流程

    1. 初始化:

      • cnt[0] = 1
      • ans = 0
    2. 遍历数组:

      • 计算前缀异或和 b[i]
      • 查询 cnt[b[i] ^ x]
      • 累加到答案
      • 更新 cnt[b[i]]

    代码实现(C++)

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N = 1e5 + 10;
    
    int a[N], b[N];
    
    int main() {
        int n, x;
        cin >> n >> x;
    
        unordered_map<int, int> cnt;
        cnt[0] = 1;
    
        ll ans = 0;
    
        for(int i = 1; i <= n; i++) {
            cin >> a[i];
            b[i] = b[i - 1] ^ a[i];
    
            if(cnt.count(b[i] ^ x)) {
                ans += cnt[b[i] ^ x];
            }
    
            cnt[b[i]]++;
        }
    
        cout << ans;
        return 0;
    }
    
    • 0
      @ 2026-3-9 16:03:09

      首先先写一个异或前缀和数组的预处理,这个问题求区间实际上可以用i和j枚举所有开始和结尾,然后利用[l,r]区间的异或前缀和为s[r]^s[l-1]来暴力,但是复杂度是n方。换一种思路,这里利用一下异或的性质,我们要求s[r]^s[l-1]=x的情况,这实际上等价于求s[r]^x=s[l-1],这是异或运算的性质,那么我们可以枚举所有可能的s[l-1],储存其值和出现的次数l-1的取值范围实际上就是0到r-1,最后统计有多少匹配的并加和即可。

      import sys
      input = lambda:sys.stdin.readline().strip()
      
      n, x = map(int, input().split())
      a = [0] + list(map(int, input().split()))
      s = [0] * (n + 1)
      
      for i in range(1, n + 1):
          s[i] = s[i-1] ^ a[i]
      
      from collections import defaultdict
      count = defaultdict(int)
      ans = 0
      
      for r in range(1, n + 1):
          count[s[r-1]] += 1
          tar = s[r] ^ x
          if tar in count:
              ans += count[tar]
      print(ans)
      
      • 1

      信息

      ID
      456
      时间
      1000ms
      内存
      256MiB
      难度
      7
      标签
      递交数
      133
      已通过
      35
      上传者