问题描述
小R定义了一个长度为 m 的数组 b 的权值为:1×b_1 + 2×b_2 + 3×b_3 + ... + m×b_m。
现在小R有一个长度为 n 的数组 a,她想知道所有子数组的权值和是多少,并且答案需要对 10^9 + 7 取模。
测试样例
样例1:
输入:
n = 3, a = [1, 2, 3]
输出:33
样例2:
输入:
n = 4, a = [4, 5, 6, 7]
输出:203
样例3:
输入:
n = 2, a = [10, 20]
输出:80
分析
问题理解
题目要求我们计算一个长度为 n 的数组 a 的所有子数组的权值和,并且对结果取模 10^9 + 7。子数组的权值定义为:1×b_1 + 2×b_2 + 3×b_3 + ... + m×b_m,其中 b 是子数组,m 是子数组的长度。
数据结构的选择逻辑
- 数组:我们使用数组
a来存储输入数据。 - 子数组:子数组是数组
a的连续子序列。
算法步骤
- 遍历所有子数组:我们需要遍历所有可能的子数组。对于每个子数组,计算其权值。
- 计算权值:对于每个子数组
b,计算其权值1×b_1 + 2×b_2 + 3×b_3 + ... + m×b_m。 - 累加权值:将每个子数组的权值累加到总权值和
total_weight中。 - 取模操作:在每次累加时,对结果取模
10^9 + 7以防止溢出。
难点分析
- 子数组的遍历:遍历所有子数组的时间复杂度是
O(n^3),因为我们需要三重循环:外层循环确定子数组的起始位置,中层循环确定子数组的结束位置,内层循环计算子数组的权值。 - 权值的计算:对于每个子数组,我们需要计算其权值。这个计算过程本身是线性的,但因为子数组的数量非常多,整体的时间复杂度会非常高。
- 取模操作:在每次累加时,需要对结果取模
10^9 + 7,以防止溢出。这个操作需要小心处理,确保不会因为溢出导致结果错误。 - 优化空间:直接遍历所有子数组会导致时间复杂度过高,需要考虑如何优化算法,减少不必要的计算。
优化思路
- 动态规划:可以考虑使用动态规划来减少重复计算。例如,可以记录每个位置的贡献,避免重复计算子数组的权值。
- 前缀和:使用前缀和数组来快速计算子数组的和,从而减少计算权值的时间复杂度。
代码
def solution(n: int, a: list) -> int:
MOD = 10**9 + 7
# 初始化总权值和
total_weight = 0
# 遍历所有可能的子数组
for start in range(n):
for end in range(start, n):
# 计算当前子数组的权值
current_weight = 0
for i in range(start, end + 1):
current_weight += (i - start + 1) * a[i]
# 累加到总权值和
total_weight = (total_weight + current_weight) % MOD
return total_weight
if __name__ == '__main__':
print(solution(3, [1, 2, 3]) == 33)
print(solution(4, [4, 5, 6, 7]) == 203)
print(solution(2, [10, 20]) == 80)
解法分析
- 初始化总权值和:使用变量
total_weight来存储所有子数组的权值和。 - 遍历所有子数组:使用两个嵌套循环来遍历所有可能的子数组。外层循环确定子数组的起始位置
start,内层循环确定子数组的结束位置end。 - 计算当前子数组的权值:对于每个子数组
a[start:end+1],使用一个内层循环计算其权值current_weight。 - 累加权值:将每个子数组的权值累加到
total_weight中,并在每次累加时对结果取模10^9 + 7。
时间复杂度分析
- 外层循环:遍历所有可能的起始位置
start,时间复杂度为O(n)。 - 中层循环:对于每个起始位置
start,遍历所有可能的结束位置end,时间复杂度为O(n)。 - 内层循环:对于每个子数组
a[start:end+1],计算其权值,时间复杂度为O(n)。
因此,总的时间复杂度为 O(n^3)。
空间复杂度分析
- 额外空间:除了输入数组
a外,只使用了常数级别的额外空间(如total_weight和current_weight),因此空间复杂度为O(1)。