豆包MarsCode AI 刷题

109 阅读3分钟

小 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