📅  最后修改于: 2023-12-03 14:58:32.322000             🧑  作者: Mango
本题涉及对于整数数组的计算。
给出一个长度为 $n$ 的整数数组 $A$, 以及两个整数 $l$ 和 $r$。 编写一个程序以确定 $A$ 中所有子数组 $A[i:j]$ 的和之和,并返回结果对 $10^9+7$ 取余数的结果。
举个例子,如果 $A=[1, 2, 3]$, $l=1$, $r=2$, 则可能的子区域为 $[1], [2], [3], [1, 2], [2, 3]$ and $[1, 2, 3]$, 其中 $[1, 2]$ and $[2, 3]$ 的和均在区间 $[l, r]$ 中。
输入格式:
输入
3
1 2 3
1 2
输出
6
解释
可能的子区域为 $[1], [2], [3], [1,2], [2,3]$ 和 $[1,2,3]$,其中 $[1,2]$ 和 $[2,3]$ 的和均在区间 $[1,2]$ 中,总和为 $3 + 5 = 8$,对应的答案为 $8%1000000007=8$。
这道题目实际上要求的是数组 $A$ 的所有子区间中和在 $[l,r]$ 之间的子区间和的和。对于这道题目,我们可以计算出所有子区间的和,再从中选取和在 $[l,r]$ 之间的子区间和,最后对结果取模。
因此,我们需要计算出所有子区间的和。具体来说,对于 $[i,j]$ 这个区间,其和为 $\sum_{k=i}^j A[k]$。
我们可以使用两重循环来计算出所有的子区间和:
sums = []
for i in range(n):
for j in range(i,n):
sub_array = A[i:j+1]
sub_sum = sum(sub_array)
sums.append(sub_sum)
其中,sums
列表用于记录所有的子区间和。由于子区间可能非常多,因此时间复杂度为 $O(n^3)$,无法通过本题。
现在的关键在于如何优化这个算法。注意到每一个子区间是由相邻的子区间转移而来的。例如,对于一个数组 $A=[1,2,3,4]$,其子区间包括:
[1]
[2]
[3]
[4]
[1,2]
[2,3]
[3,4]
[1,2,3]
[2,3,4]
[1,2,3,4]
我们可以观察到,左侧的其中前4个子区间,是由左侧第一个子区间与右侧第一个元素组合而来的。后5个子区间中,左侧的其中前3个子区间,是由第5个子区间和右侧第二个元素组合而来的。再往右推,就可以看出所有子区间都是由相邻的子区间转移而来的。
因此,这个算法的优化方向就很明显了:计算出所有长度为 $k$ 的子区间的和,再使用这个和去计算长度为 $k+1$ 的子区间的和。直到计算出所有长度为 $n$ 的子区间的和为止。
具体来说,我们可以通过计算前缀和 $\sum_{i=1}^j A[i]$ 去计算出任意子区间 $[i,j]$ 的和。假设 prefix_sum
是数组 $A$ 的前缀和,即 prefix_sum[i]
表示 $A$ 中前 $i$ 个元素的和,则区间 $[i,j]$ 的和为:
$$\sum_{k=i}^j A[k] = \sum_{k=1}^j A[k] - \sum_{k=1}^{i-1} A[k] = prefix_sum[j]-prefix_sum[i-1]$$
有了前缀和,我们只需要计算长度为 $k$ 的子区间的和,即
for k in range(1, n+1):
for i in range(n-k+1):
j = i + k - 1
sub_sum = prefix_sum[j] - prefix_sum[i-1]
sums.append(sub_sum)
最终,我们只需要在所有子区间的和中,选取和在区间 $[l, r]$ 中的子区间的和,并对结果取模,即可得到答案。具体实现参见代码片段。
def subarray_sum(n, A, l, r):
MOD = 1000000007
prefix_sum = [0] * (n+1)
for i in range(1,n+1):
prefix_sum[i] = prefix_sum[i-1] + A[i-1]
sums = []
for k in range(1, n+1):
for i in range(n-k+1):
j = i + k - 1
sub_sum = prefix_sum[j] - prefix_sum[i-1]
sums.append(sub_sum)
ans = 0
for sub_sum in sums:
ans += (l <= sub_sum <= r)
return ans % MOD
返回的是markdown格式的文本。
## 题目14
本题涉及对于整数数组的计算。
### 问题描述
给出一个长度为 $n$ 的整数数组 $A$, 以及两个整数 $l$ 和 $r$。 编写一个程序以确定 $A$ 中所有子数组 $A[i:j]$ 的和之和,并返回结果对 $10^9+7$ 取余数的结果。
举个例子,如果 $A=[1, 2, 3]$, $l=1$, $r=2$, 则可能的子区域为 $[1], [2], [3], [1, 2], [2, 3]$ and $[1, 2, 3]$, 其中 $[1, 2]$ 和 $[2, 3]$ 的和均在区间 $[l, r]$ 中。
**输入格式:**
- 第一行输入整数 $n$,表示整数数组的长度 $(1\leq n\leq 10^5)$;
- 第二行输入 $n$ 个整数,分别表示 $A[1],A[2],\cdots,A[n]$ $(0\leq A[i]\leq 10^9)$ ;
- 第三行输入两个整数 $l$ 和 $r$ $(1\leq l\leq r\leq n)$。
### 示例
输入
3 1 2 3 1 2
输出
6
解释
可能的子区域为 $[1], [2], [3], [1,2], [2,3]$ 和 $[1,2,3]$,其中 $[1,2]$ 和 $[2,3]$ 的和均在区间 $[1,2]$ 中,总和为 $3 + 5 = 8$,对应的答案为 $8\%1000000007=8$。
### 解题思路
这道题目实际上要求的是数组 $A$ 的所有子区间中和在 $[l,r]$ 之间的子区间和的和。对于这道题目,我们可以计算出所有子区间的和,再从中选取和在 $[l,r]$ 之间的子区间和,最后对结果取模。
因此,我们需要计算出所有子区间的和。具体来说,对于 $[i,j]$ 这个区间,其和为 $\sum_{k=i}^j A[k]$。
我们可以使用两重循环来计算出所有的子区间和:
``` python
sums = []
for i in range(n):
for j in range(i,n):
sub_array = A[i:j+1]
sub_sum = sum(sub_array)
sums.append(sub_sum)
其中,sums
列表用于记录所有的子区间和。由于子区间可能非常多,因此时间复杂度为 $O(n^3)$,无法通过本题。
现在的关键在于如何优化这个算法。注意到每一个子区间是由相邻的子区间转移而来的。例如,对于一个数组 $A=[1,2,3,4]$,其子区间包括:
[1]
[2]
[3]
[4]
[1,2]
[2,3]
[3,4]
[1,2,3]
[2,3,4]
[1,2,3,4]
我们可以观察到,左侧的其中前4个子区间,是由左侧第一个子区间与右侧第一个元素组合而来的。后5个子区间中,左侧的其中前3个子区间,是由第5个子区间和右侧第二个元素组合而来的。再往右推,就可以看出所有子区间都是由相邻的子区间转移而来的。
因此,这个算法的优化方向就很明显了:计算出所有长度为 $k$ 的子区间的和,再使用这个和去计算长度为 $k+1$ 的子区间的和。直到计算出所有长度为 $n$ 的子区间的和为止。
具体来说,我们可以通过计算前缀和 $\sum_{i=1}^j A[i]$ 去计算出任意子区间 $[i,j]$ 的和。假设 prefix_sum
是数组 $A$ 的前缀和,即 prefix_sum[i]
表示 $A$ 中前 $i$ 个元素的和,则区间 $[i,j]$ 的和为:
$$\sum_{k=i}^j A[k] = \sum_{k=1}^j A[k] - \sum_{k=1}^{i-1} A[k] = prefix_sum[j]-prefix_sum[i-1]$$
有了前缀和,我们只需要计算长度为 $k$ 的子区间的和,即
for k in range(1, n+1):
for i in range(n-k+1):
j = i + k - 1
sub_sum = prefix_sum[j] - prefix_sum[i-1]
sums.append(sub_sum)
最终,我们只需要在所有子区间的和中,选取和在区间 $[l, r]$ 中的子区间的和,并对结果取模,即可得到答案。具体实现参见代码片段。
def subarray_sum(n, A, l, r):
MOD = 1000000007
prefix_sum = [0] * (n+1)
for i in range(1,n+1):
prefix_sum[i] = prefix_sum[i-1] + A[i-1]
sums = []
for k in range(1, n+1):
for i in range(n-k+1):
j = i + k - 1
sub_sum = prefix_sum[j] - prefix_sum[i-1]
sums.append(sub_sum)
ans = 0
for sub_sum in sums:
ans += (l <= sub_sum <= r)
return ans % MOD