小 R 的权值计算思路讲解
一、问题分析
我们要计算给定数组 a 的所有子数组的权值和,这里数组 a 的长度为 n,而权值的定义是对于长度为 m 的数组 b,其权值为 1×b_1 + 2×b_2 + 3×b_3 +... + m×b_m。这意味着我们需要找出一种方法来系统地考虑每个子数组,并计算它们的权值,最后将所有子数组的权值累加起来。
二、思路步骤
(一)从单个元素的贡献入手
我们先思考数组中的单个元素对最终结果的贡献。对于数组 a 中的元素 a[i](这里 i 是从 0 到 n - 1 的索引),它会在多个子数组中出现。具体来说,它在包含它自身且起始位置从 0 到 i,结束位置从 i 到 n - 1 的所有子数组中出现。
(二)计算元素出现次数
那么 a[i] 在子数组中出现的次数怎么计算呢?通过分析可以发现,a[i] 出现的次数等于以它为中心,向左可以有 i 种选择(包括它自身),向右可以有 n - i 种选择,所以它总共出现的次数就是 (i + 1)×(n - i)。
(三)计算单个元素对权值和的贡献
由于每个元素 a[i] 在权值计算中有一个系数,这个系数是它在子数组中的位置,我们可以根据这个来计算它对整个权值和的贡献。因为它出现了 (i + 1)×(n - i) 次,并且它在权值计算中的系数是 i + 1,所以它对权值和的贡献就是 a[i]×(i + 1)×(n - i)×(i + 1)。但是这里我们还需要考虑权值定义中的系数计算方式,其实就是一个等差数列求和的形式,对于长度为 k 的子数组,其权值系数之和为 k×(k + 1) / 2。所以对于 a[i],我们还需要在前面的计算结果上再乘以 (i + 1) / 2(这里为了避免除法运算在取模运算中的复杂性,我们可以通过计算 2 的模逆元来实现除法的效果)。
(四)累加所有元素的贡献
最后,我们只需要遍历数组 a 中的每个元素,按照上述方法计算每个元素对权值和的贡献,并将它们累加起来,同时在每一步累加过程中对 10^9 + 7 取模,这样就可以得到所有子数组的权值和。
代码如下:
def solution(n: int, a: list) -> int:
MOD = 10**9 + 7
inv2 = pow(2, MOD - 2, MOD) # 计算2的模逆元
total = 0
for i in range(1, n + 1):
ai = a[i - 1]
term = ai * (n - i + 1) % MOD # a[i] * (n - i + 1)
term = term * i % MOD # * i
term = term * (i + 1) % MOD # * (i + 1)
term = term * inv2 % MOD # / 2
total = (total + term) % MOD # 累加到总和
return total
if name == 'main':
print(solution(3, [1, 2, 3]) == 33) # 输出: True
print(solution(4, [4, 5, 6, 7]) == 203) # 输出: True
print(solution(2, [10, 20]) == 80) # 输出: True