214小R的权值计算

题解

问题理解

给定一个长度为 n 的数组 a,小 R 定义任意子数组的权值为 1×b₁ + 2×b₂ + ... + m×bₘ,其中 m 是子数组的长度,b₁, b₂, ..., bₘ 是子数组中的元素。要求计算所有子数组权值的和,结果需对 10^9 + 7 取模。

解题思路

b1 b2 b3 b4 b5
b1+2b2 b2+2b3 b3+2b4 b4+2b5
b1+2b2+3b3 b2+2b3+3b4 b3+2b4+3b5
b1+2b2+3b3+4b4 b2+2b3+3b4+4b5
b1+2b2+3b3+4b4+5b5
根据规律可以看出长度为 length 的子数组转移的时候,只需要加上 length*a[i] - (s[i-1] - s[i-length-1])即可

  1. 前缀和计算
    使用前缀和 s 来快速计算任意子数组的元素和,s[i] 表示前 i 个元素的和。

  2. 权值计算
    对于每个子数组长度 length,遍历所有可能的子数组,计算当前子数组的权值 cur

    • 初始时,计算第一个长度为 length 的子数组的权值。
    • 随着窗口的滑动,通过更新 cur 来计算下一个子数组的权值:
      1
      cur += length * a[i] - (s[i - 1] - s[i - length - 1])
      这里,length * a[i] 是新加入元素对权值的贡献,(s[i - 1] - s[i - length - 1]) 是窗口内之前元素权值的调整。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mod = int(1e9 + 7)
from itertools import accumulate

def solution(n: int, a: list) -> int:
res = 0
a = [0] + a
s = list(accumulate(a))
# 枚举子数组的长度
for length in range(1, n + 1):
cur = 0
for i in range(1, length + 1):
cur += a[i] * i
res = (res + cur) % mod
for i in range(length + 1, n + 1):
cur += length * a[i] - (s[i - 1] - s[i - length - 1])
res = (res + cur) % mod
return res % mod

if __name__ == '__main__':
print(solution(3, [1, 2, 3]) == 33)
print(solution(4, [4, 5, 6, 7]) == 203)
print(solution(2, [10, 20]) == 80)

214小R的权值计算
https://kongshuilinhua.github.io/2024/12/25/214小R的权值计算/
作者
FireFLy
发布于
2024年12月25日
许可协议