题解
问题理解
给定一个长度为 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])即可
-
前缀和计算: 使用前缀和
s来快速计算任意子数组的元素和,s[i]表示前i个元素的和。 -
权值计算: 对于每个子数组长度
length,遍历所有可能的子数组,计算当前子数组的权值cur。- 初始时,计算第一个长度为
length的子数组的权值。 - 随着窗口的滑动,通过更新
cur来计算下一个子数组的权值:这里,cur += length * a[i] - (s[i - 1] - s[i - length - 1])length * a[i]是新加入元素对权值的贡献,(s[i - 1] - s[i - length - 1])是窗口内之前元素权值的调整。
- 初始时,计算第一个长度为
代码实现
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)