问题描述
小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:断言,用于检查条件是否满足。
学习总结
位运算在处理二进制问题时非常高效,尤其是在需要逐位处理数据时。通过位运算可以快速获取和操作二进制位的信息。动态规划通过维护状态和状态转移来解决问题。我还明白了模运算的重要性。在处理大数问题时,模运算可以防止整数溢出,确保结果在合理范围内。