开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情
二维前缀和
- 在一个矩阵里面,计算子矩阵的和
二维前缀和的计算
-
s(i,j)以i,j为右下角的矩阵的和,a(i,j)为矩阵中的数
-
如何计算s(i,j)?
s[i][j] = s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]计算以(i,j)为右下角的矩阵的前缀和,此时,将s(i-1,j)+s(i,j-1)+a(i,j),此时以(i-1,j-1)的矩阵被减了两次,加上s(i-1,j-1),
从而求得s(i,j)
-
如何计算以(x1,y1)为左上角,(x2,y2)为右下角的子矩阵的和?
s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]
推导过程:
把以(x2,y2)的右下角的矩阵的和减去以(x1-1,y2)为右下角的矩阵的,减去以(x2,y1-1)为右下角的矩阵,此时,以(x1-1,y1-1)为右下角的矩阵被减了两次,此时需要加上一次,+s(x1-1)(y1-1)
例题
输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2
,表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。
输入格式
第一行包含三个整数 n,m,q
接下来 n行,每行包含 m个整数,表示整数矩阵。
接下来 q 行,每行包含四个整数 x1,y1,x2,y2,表示一组询问。
输出格式
共 q行,每行输出一个询问的结果。
数据范围
1≤n,m≤1000, 1≤q≤200000, 1≤x1≤x2≤n, 1≤y1≤y2≤m, −1000≤矩阵内元素的值≤1000
输入样例:
3 4 3
1 7 2 4
3 6 2 8
2 1 2 3
1 1 2 2
2 1 3 4
1 3 3 4
输出样例:
17
27
21
代码
package main
import "fmt"
var (
n int
m int
q int
a [1010][1010]int
s [1010][1010]int
)
func main() {
fmt.Scanf("%d %d %d", &n, &m, &q)
for i := 1; i <= n; i++ {
for j := 1; j <= m; j++ {
fmt.Scanf("%d", &a[i][j])
}
}
for i := 1; i <= n; i++ {
for j := 1; j <= m; j++ {
s[i][j] = s[i-1][j] + s[i][j-1] + a[i][j] - s[i-1][j-1]
}
}
var x1, y1, x2, y2 int
for i := 0; i < q; i++ {
fmt.Scanf("%d %d %d %d", &x1, &y1, &x2, &y2)
ans := s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1]
fmt.Println(ans)
}
}