原题链接
题目难度:简单
题目描述
输入一个 n 行 m 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 $x_1, y_1, x_2, y_2$,表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。
输入格式
第一行包含三个整数 n,m,q。
接下来 n 行,每行包含 m 个整数,表示整数矩阵。
接下来 q 行,每行包含四个整数 $x_1, y_1, x_2, y_2$,表示一组询问。
输出格式
共 q 行,每行输出一个询问的结果。
数据范围
1≤n,m≤1000,
1≤q≤200000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤矩阵内元素的值≤1000
输入样例:
1 | 3 4 3 |
输出样例:
1 | 17 |
题目分析
对于一维的前缀和,就是求某一段的前缀和,这道题是二维数组中的前缀和,是求任意区域的数字之和
如果每一次询问都是暴力算的话,复杂度其实是极高的,因此同样的,我们还是需要用前缀和的做法
对于这个前缀和矩阵,其中的每一个数,就代表了包括这个数和他左上角的所有数的和
第一个问题就是如何计算这个前缀和矩阵,我们的公式是什么,这里我们就可以运用一下数学中容斥原理的思想,或者可以理解为图形面积的加减
例如
我们是想要计算(2,3)的数字,实际上就需要用(1,3)的数字加上(2,2)的数字,也就是黄色(包括绿色)加上蓝色(包括绿色),但是这样我们就把绿色加了两遍,因此需要减去一个绿色的(1,2),这样我们就算除了原本(2,3)对应的数字剩下数字的和,最后只需要加上(2,3)原本的数字即可
用公式表示就是
$S_{x,y}=S_{x-1,y}+S_{x,y-1}-S_{x-1,y-1}+a_{x,y}$
利用这个公式就可以计算出前缀和数组了
第二个问题就是,假设我们已经有了前缀和数组,我们如何快速算出子矩阵的和是多少,这里的数学原理是与之前一样的
我们想要计算蓝色部分的子矩阵和,其实只需要用对应的前缀和矩阵的(3,3)(包括黄色绿色橙色),减去(1,3)(包括橙色绿色),减去(3,1)(包括黄色绿色),这里绿色被减去了两次,因此我们需要再加回来一次,加上(1,1)(绿色)即可
我们使用$(x_1,y_1)$表示子矩阵左上角的坐标,用$(x_2,_y2)$表示右下角的坐标,最终结果用公式表示就是
$ans = S_{x_2,y_2}-S_{x_2,y_1-1}-S_{x_1-1,y_2}+S_{x_1-1,y_1-1}$
这就是二维前缀和的思想
示例代码
1 |
|