一维前缀
解题思路
看到“区间之和”问题,直接想到“前缀和”
前缀和的核心公式: sum[i]=sum[i−1]+a[i]
利用前缀和求区间和 [l,r] 的公式: 区间和=sum[r]−sum[l−1]
解题步骤模板
-
输入数组:
-
读取数组长度 n 和查询次数 m。
-
读取数组 a 的每个元素。
-
-
计算前缀和:
-
初始化一个前缀和数组 sum,长度为 n+1(方便处理边界情况)。
-
遍历数组 a,计算前缀和
for (int i = 1; i <= n; i++) {sum[i] = sum[i - 1] + a[i]; }
-
-
处理查询:
-
对于每个查询 [l,r],直接利用前缀和公式计算区间和
System.out.println(sum[r] - sum[l - 1]);
-
示例代码模板
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);// 输入数组长度和查询次数int n = scan.nextInt();int m = scan.nextInt();// 输入数组int[] a = new int[n + 1];int[] sum = new int[n + 1];// 计算前缀和for (int i = 1; i <= n; i++) {a[i] = scan.nextInt();sum[i] = sum[i - 1] + a[i];}// 处理查询for (int i = 0; i < m; i++) {int l = scan.nextInt();int r = scan.nextInt();System.out.println(sum[r] - sum[l - 1]);}scan.close();}
}
思维导图
-
看到“区间之和” → 想到“前缀和”
-
公式:sum[i]=sum[i−1]+a[i]
-
区间和:sum[r]−sum[l−1]
-
-
实现步骤:
-
输入数组和查询。
-
计算前缀和。
-
处理查询并输出结果。
-
训练方法
-
遇到“区间之和”问题,直接写前缀和公式: sum[i]=sum[i−1]+a[i] 区间和=sum[r]−sum[l−1]
-
多做类似题目,强化这种思维模式。例如:蓝桥官网、力扣等平台上的区间和问题。
二维前缀和
问题描述
给定一个 n×mn×m 大小的矩阵 AA。
给定 qq 组查询,每次查询为给定 44 个正整数 x1,y1,x2,y2x1,y1,x2,y2,你需要输出 ∑i=x1x2∑j=y1y2Ai,j∑i=x1x2∑j=y1y2Ai,j 的值。
输入格式
第一行输入 33 个正整数 n,m,qn,m,q。(1≤n,m≤103,1≤q≤1051≤n,m≤103,1≤q≤105)
接下来 nn 行每行输入 mm 个整数,表示 Ai,jAi,j。(−103≤Ai,j≤103,1≤i≤n,1≤j≤m)(−103≤Ai,j≤103,1≤i≤n,1≤j≤m)
接下来 qq 行,每行输入 44 个正整数 x1,y1,x2,y2x1,y1,x2,y2。(1≤x1≤x2≤n,1≤y1≤y2≤m)(1≤x1≤x2≤n,1≤y1≤y2≤m)
输出格式
对于每次查询,输出一个整数,表示查询的子矩阵的和。
样例输入
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
解题思路
1. 看到“二维区间和”问题,直接想到“二维前缀和”
-
二维前缀和的核心公式:
sum[i][j]=sum[i][j−1]+sum[i−1][j]−sum[i−1][j−1]+a[i][j] -
查询子矩阵和的公式:
区间和=sum[x2][y2]−sum[x2][y1−1]−sum[x1−1][y2]+sum[x1−1][y1−1]
2. 实现步骤
-
输入矩阵:
-
读取矩阵的行数
n
、列数m
和查询次数q
。 -
读取矩阵
a
的每个元素。
-
-
计算二维前缀和:
-
初始化一个二维前缀和数组
sum
,大小为 (n+1)×(m+1)。 -
遍历矩阵
javaa
,计算每个位置的二维前缀和:复制
for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {a[i][j] = scan.nextInt();sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + a[i][j];} }
-
-
处理查询:
-
对于每个查询 (x1,y1) 到 (x2,y2),利用二维前缀和公式计算子矩阵和:
java复制
System.out.println(sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1]);
-
-
输出结果:
-
对每个查询输出对应的子矩阵和。
-
代码模板
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);// 输入矩阵的行数、列数和查询次数int n = scan.nextInt();int m = scan.nextInt();int q = scan.nextInt();// 创建数组存储原始矩阵和前缀和int[][] a = new int[n + 1][m + 1];int[][] sum = new int[n + 1][m + 1];// 计算二维前缀和for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {a[i][j] = scan.nextInt();sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + a[i][j];}}// 处理查询for (int i = 0; i < q; i++) {int x1 = scan.nextInt();int y1 = scan.nextInt();int x2 = scan.nextInt();int y2 = scan.nextInt();System.out.println(sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1]);}scan.close();}
}
总结
-
看到“二维区间和”问题,直接想到“二维前缀和”。
-
核心公式:
-
二维前缀和:sum[i][j]=sum[i][j−1]+sum[i−1][j]−sum[i−1][j−1]+a[i][j]
-
查询子矩阵和:区间和=sum[x2][y2]−sum[x2][y1−1]−sum[x1−1][y2]+sum[x1−1][y1−1]
-
-
实现步骤:
-
输入矩阵和查询。
-
计算二维前缀和。
-
处理查询并输出结果。
-
相关的习题练习
小秋的矩阵
问题描述
给你一个 nn 行 mm 列只包含 00 和 11 的矩阵,求它的所有子矩阵中,是方阵而且恰好包含 kk 个 00 的数量。
方阵是行数和列数相等的矩阵。
子矩阵是从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序),被称为原矩阵的一个子矩阵。
输入格式
第 11 行输入 33 个整数 n,m,kn,m,k,表示矩阵的行数,列数和所求子矩阵包含 00 的数量。
接下来 nn 行,每行输入 mm 个整数,第 ii 表示给定矩阵的第 ii 行。
输出格式
输出仅一行,包含 11 个整数,表示答案。
样例输入
3 4 2
0 1 1 0
1 0 0 1
0 1 0 0
样例输出
4
说明
共有 44 个阶数为 22 的方阵符合条件,左上角的坐标分别为 (1,1),(1,2),(1,3),(2,1)(1,1),(1,2),(1,3),(2,1)。
评测数据规模
对于 2020% 的评测数据,1≤n×m≤1031≤n×m≤103。
对于 4040% 的评测数据,1≤n×m≤1051≤n×m≤105。
对于 100100% 的评测数据,1≤n×m≤1061≤n×m≤106,0≤k≤n×m0≤k≤n×m。
代码实现
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner scan = new Scanner(System.in);// 读取行数、列数和目标零的个数int n = scan.nextInt();int m = scan.nextInt();int k = scan.nextInt();// 创建数组存储原始矩阵和前缀和int[][] tur = new int[n + 1][m + 1];int[][] sum = new int[n + 1][m + 1];// 输入矩阵并计算前缀和for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {tur[i][j] = scan.nextInt();sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + tur[i][j];}}// 计数符合条件的子矩阵int count = 0;// 遍历所有可能的正方形子矩阵的大小for (int size = 1; size <= Math.min(n, m); size++) {// 遍历所有可能的起始位置for (int i = 1; i <= n - size + 1; i++) {for (int j = 1; j <= m - size + 1; j++) {// 计算子矩阵的右下角坐标int x2 = i + size - 1;int y2 = j + size - 1;// 计算子矩阵的和int total = sum[x2][y2] - sum[x2][j - 1] - sum[i - 1][y2] + sum[i - 1][j - 1];// 计算子矩阵中零的个数int tmp = size * size - total;// 如果符合条件,计数器加1if (tmp == k) {count++;}}}}// 输出结果System.out.println(count);scan.close();}
}
自学蓝桥杯笔记,希望我们可以一起学习!