AcWing 796. 子矩阵的和——算法基础课题解
内容提要
这篇文章介绍了一个关于子矩阵和的问题。给定一个n行m列的整数矩阵和q个询问,每个询问包含一个子矩阵的左上角和右下角坐标,要求计算子矩阵中所有数的和。文章给出了解题思路和具体的代码实现。
延伸解读
二维前缀和的核心思想
文章通过二维前缀和将子矩阵求和转化为常数时间操作。预处理时,每个位置存储从左上角到该位置所有元素的和,利用容斥原理计算。查询时,通过四个前缀和值的加减得到结果。这种方法将每次查询的复杂度从O(n*m)降为O(1),适合大量查询。
数据范围与性能考量
题目中n和m最大为1000,q最大为200000。若每次查询都遍历子矩阵,最坏情况下总操作数可达2e11,无法接受。而二维前缀和预处理需O(n*m)时间,每次查询O(1),总时间O(n*m + q),在合理范围内。这体现了前缀和算法处理高并发查询的优势。
实现细节与语言差异
文章提供了C++和Go两种实现。C++代码使用scanf/printf进行快速输入输出,并注意数组下标从1开始以简化边界处理。Go代码使用bufio进行缓冲读写,并动态分配二维切片。两者都遵循相同的核心公式,但需注意Go中切片初始化和输入输出的效率优化。
边界处理与公式推导
公式S[x2,y2] - S[x1-1,y2] - S[x2,y1-1] + S[x1-1,y1-1]基于容斥原理,确保不重不漏。代码中下标从1开始,避免了越界检查。对于x1=1或y1=1的情况,S[0][*]和S[*][0]初始为0,公式依然成立。这种设计简化了边界条件,是算法竞赛中的常见技巧。
Q&A
如何计算子矩阵的和?
使用前缀和数组,公式为:S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]。
输入数据的格式是什么?
第一行包含三个整数n、m、q,接下来n行是矩阵数据,最后q行是询问的坐标。
这个问题的时间复杂度如何?
由于使用前缀和数组,查询每个子矩阵的和的时间复杂度为O(1),整体复杂度为O(n*m + q)。
可以使用哪些编程语言实现这个算法?
文章提供了C++和Go语言的具体实现代码。
数据范围是什么?
数据范围为1≤n,m≤1000,1≤q≤200000,矩阵元素值范围为−1000到1000。
如何处理多个询问?
可以在构建前缀和数组后,依次处理每个询问,利用前缀和快速计算结果。