[R4E] 区间异或和

  • 难度 入门
  • 时限 1s
  • 空限 512m
  • 位运算前缀和

思路

设前缀异或 Si=A1A2AiS_i = A_1 \oplus A_2 \oplus \dots \oplus A_iS0=0S_0 = 0),则

XORsum(l,r)=Sl1SrXORsum(l, r) = S_{l-1} \oplus S_r

题目所求即所有二元组 (i,j)(i, j)0i<jn0 \le i < j \le n)的 SiSjS_i \oplus S_j 之和。

异或运算按位独立,对第 bb 位,只有两个前缀在这一位上不同时才对答案贡献 2b2^b。设 n+1n+1 个前缀中第 bb 位为 11 的有 onesones 个,则该位贡献 ones×(n+1ones)×2bones \times (n+1-ones) \times 2^b。逐位累加即可。

复杂度:时间 O(nlogV)O(n \log V)V=maxAiV = \max A_i),空间 O(logV)O(\log V)

仓颉实现

import std.convert.*
import std.env.*

func solve() {
    let reader = getStdIn()
    let n = Int64.parse(reader.readln().getOrThrow())
    let nn = n
    let a = reader.readln().getOrThrow().split(" ", removeEmpty: true).map({ p => Int64.parse(p) })
    let cnt = Array<Int64>(32, { _ => 0 })
    var x: Int64 = 0
    for (v in a) {
        x ^= v
        for (b in 0..32) {
            if (((x >> b) & 1) == 1) {
                cnt[b] += 1
            }
        }
    }
    let total = nn + 1
    var ans: Int64 = 0
    for (b in 0..32) {
        let ones = cnt[b]
        ans += ones * (total - ones) * (Int64(1) << b)
    }
    println(ans)
}

main() {
    solve()
}