前缀和 --- 二维前缀和
题目链接(牛客网)
给你一个 n 行 m 列的矩阵 A ,下标从1开始。
接下来有 q 次查询,每次查询输入 4 个参数 x1 , y1 , x2 , y2
请输出以 (x1, y1) 为左上角 , (x2,y2) 为右下角的子矩阵的和,
输入描述:
第一行包含三个整数n,m,q.
接下来n行,每行m个整数,代表矩阵的元素
接下来q行,每行4个整数x1, y1, x2, y2,分别代表这次查询的参数
问题分析
如果我们能处理出来从 [0, 0] 位置到 [i, j] 位置这⽚区域内所有元素的累加和,就可以在 O(1) 的时间内,搞定矩阵内任意区域内所有元素的累加和。因此我们接下来仅需完成两步即可:
第⼀步:前缀和矩阵
在矩阵的最上⾯和最左边添加上⼀⾏和⼀列0,这样我们就可以省去⾮常多的边界条件的处理
递推⽅程:
其实这个递推⽅程⾮常像我们⼩学做过求图形⾯积的题,我们可以将 [0, 0] 位置到 [i, j] 位置这段区域分解成下⾯的部分:
递推⽅程是:sum[i][j]=sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1]+matrix[i - 1][j - 1]
第⼆步:使⽤前缀和矩阵
sum[row2][col2]-sum[row2][col1 - 1]-sum[row1 - 1][col2]+sum[row1 - 1][col1 - 1]
代码解决
public static void main2(String[] args) {Scanner in = new Scanner(System.in);//读入数据int n = in.nextInt(),m = in.nextInt(),q = in.nextInt();int[][] arr = new int[n+1][m+1];for (int i = 1;i<=n;i++){for (int j = 1; j <=m; j++) {arr[i][j] = in.nextInt();}}//预处理一个前缀和数组long[][] dp = new long[n+1][m+1];for (int i = 1; i <=n ; i++) {for (int j = 1; j <=m ; j++) {dp[i][j] = dp[i-1][j] + dp[i][j-1] +arr[i][j] - dp[i-1][j-1];}}//使用前缀和数组while (q>0){int x1 = in.nextInt(),y1 = in.nextInt(),x2 = in.nextInt(),y2 = in.nextInt();System.out.println(dp[x2][y2] - dp[x1-1][y2] - dp[x2][y1-1] + dp[x1-1][y1-1]);q--;}}