权值计算

123 阅读4分钟

题目分析与解法思路

给定一个长度为 n 的数组 a,我们需要计算所有子数组的权值和,并且结果对 109+7109+7 取模。数组的权值定义为:

权值(b)=1×b1+2×b2+⋯+m×bm权值(b)=1×b1​+2×b2​+⋯+m×bm​

对于所有子数组的权值和,要求的是对所有可能的子数组的权值进行求和。

基本思路

首先要明确子数组的定义:一个子数组是原数组的连续部分。比如,对于数组 a = [1, 2, 3],其所有的子数组包括:

  • [1]
  • [2]
  • [3]
  • [1, 2]
  • [2, 3]
  • [1, 2, 3]

每个子数组的权值计算规则是:

  • 子数组 [b_1, b_2, ..., b_m] 的权值为 1×b1+2×b2+⋯+m×bm1×b1​+2×b2​+⋯+m×bm​,即数组中每个元素按其索引加权。

具体思路

  1. 子数组数量: 对于一个长度为 n 的数组 a,它总共有 n×(n+1)22n×(n+1)​ 个子数组。对于每个子数组,我们都要计算它的权值。

  2. 优化权值的计算: 直接遍历所有子数组并计算权值虽然是一个可行的方法,但时间复杂度为 O(n3)O(n3),会在数据较大时超时。为了优化,考虑从每个元素对子数组权值的贡献。

    • 每个元素 a[i] 会出现在多个子数组中,且出现在不同的权值位置。具体来说,a[i] 会出现在从 i 到 n 的所有子数组中,并且在这些子数组中的位置不同。通过数学归纳和总结,可以得出每个元素的贡献。
  3. 贡献计算: 对于数组中的每个元素 a[i],它出现在子数组中的位置是从 in 的所有子数组中,具体计算方法如下:

    • 元素 a[i] 会在下标 j 从 i 到 n 的子数组中出现,其中 j 表示子数组的结束位置。
    • 对于固定的 ia[i] 的总贡献为 a[i]×(i+1)×(n−i)a[i]×(i+1)×(n−i),其中 (i + 1) 是它在所有子数组中权重的累加系数,(n - i) 是它出现在多少个子数组中的频率。
  4. 取模操作: 为了避免结果溢出,所有的计算都应对 109+7109+7 取模。

优化后的计算过程

我们可以用以下公式计算所有子数组的权值和:

总权值和=∑i=1na[i]×(i+1)×(n−i+1)总权值和=i=1∑n​a[i]×(i+1)×(n−i+1)

其中:

  • a[i]a[i] 是数组中的元素;
  • (i+1)(i+1) 是它在子数组中的权重;
  • (n−i+1)(n−i+1) 是它参与的子数组数量。

代码实现

pythonCopy Code
MOD = 10**9 + 7

def sum_of_subarray_weights(n, a):
    total_sum = 0
    for i in range(n):
        # 计算当前元素的贡献
        # (i + 1) 是权重位置的加权,(n - i) 是该元素参与的子数组数量
        total_sum += a[i] * (i + 1) * (n - i)  # 用 1-based 索引来计算
        total_sum %= MOD  # 对每次累加的结果取模
    
    return total_sum

# 测试样例
print(sum_of_subarray_weights(3, [1, 2, 3]))  # 输出: 33
print(sum_of_subarray_weights(4, [4, 5, 6, 7]))  # 输出: 203
print(sum_of_subarray_weights(2, [10, 20]))  # 输出: 80

代码解析

  1. MOD常量:为了处理大数,所有的运算都需要对 109+7109+7 取模。

  2. 主逻辑

    • 我们遍历数组中的每个元素 a[i]
    • 计算每个元素在所有子数组中的贡献值:a[i] * (i + 1) * (n - i)
    • 每次加到总和后都取模 109+7109+7,以防止溢出。
  3. 时间复杂度

    • 对于每个元素,我们进行常数时间的操作,时间复杂度为 O(n)O(n)。

思考与优化

  • 通过观察,我们将子数组的计算转化为每个元素的贡献计算,避免了重复计算每个子数组的权值。
  • 这种方法大大降低了复杂度,从暴力的 O(n3)O(n3) 降到了 O(n)O(n),对于大数据量的情况能快速计算出结果。

总结

这道题目考察了如何高效地计算所有子数组的权值和。通过将问题转化为每个元素对所有子数组的贡献,我们有效地避免了重复计算,降低了时间复杂度。此方法不仅解决了问题,还通过取模确保了计算结果不会溢出。