小E的区间异或和 | 豆包MarsCode AI刷题

70 阅读2分钟

问题描述

小C拿到了一个数组,她定义一个数组的权值为数组中任意选取两个数的异或之和。具体来说,对于一个数组,每个连续子数组的任意两元素的异或值之和定义为其权值。她想知道该数组中所有可能的连续子数组的权值之和是多少,答案需要对10^9 + 7取模。

测试样例

样例1:

输入:n = 4, a = [2, 3, 1, 2]
输出:28

样例2:

输入:n = 3, a = [5, 6, 7]
输出:10

样例3:

输入:n = 2, a = [1, 10]
输出:11

样例4:

输入:n = 5, a = [1, 2, 4, 8, 16]
输出:402


分析

我们可以通过逐位处理数组中的元素,计算每个位的贡献,并最终累加得到最终结果。


具体步骤

初始化

定义模数mod = int(1e9 + 7),假设数组元素的最大值不超过 2^31,注意初始化结果。

逐位处理

外层循环遍历每个位 k。内层循环遍历数组 a,计算当前位的贡献。

计算贡献

通过 c[0] 和 c[1] 记录当前位的状态。通过 s 累加当前位的贡献。

累加结果

将当前位的贡献左移 k 位,并累加到 ans 中。

返回结果

最终返回 ans,并对 10^9 + 7 取模。

具体代码

代码如下:

def solution(n: int, a: list) -> int:
    assert n == len(a<p align=center>)</p>
    mod = int(1e9 + 7)
    m = 31
    ans = 0
    for k in range(m):
        c = [0, 0]
        s = 0
        for j, x in enumerate(a):
            b = (x >> k) & 1
            s = (s + c[1 - b] * (n - j)) % mod
            c[b] = (c[b] + j + 1) % mod
        ans = (ans + (s << k)) % mod
    return ans

知识点

位运算

x >> k:右移操作,将 x 的二进制表示向右移动 k 位。 (x >> k) & 1:获取 x 的第 k 位(从右往左数)。 s << k:左移操作,将 s 的二进制表示向左移动 k 位。

动态规划

通过维护两个计数器 c[0] 和 c[1],分别记录当前位为 0 和 1 的元素个数。 通过累加 s 来计算当前位的贡献。

模运算

(a + b) % mod:防止整数溢出,对结果取模。

数组操作

遍历数组 a,并对每个元素进行位运算和计数。

Python 特性

enumerate(a):同时获取数组的索引和值。 assert:断言,用于检查条件是否满足。

学习总结

位运算在处理二进制问题时非常高效,尤其是在需要逐位处理数据时。通过位运算可以快速获取和操作二进制位的信息。动态规划通过维护状态和状态转移来解决问题。我还明白了模运算的重要性。在处理大数问题时,模运算可以防止整数溢出,确保结果在合理范围内。