二维前缀和
简介
二维前缀和是前缀和差分中的一类,属于基础算法。通常用于求子矩阵元素的和。
假设有一个 \(n\times m\) 的矩阵,二维前缀和预处理复杂度为 \(O\left(nm\right)\) ,查询复杂度为 \(O\left(1\right)\) ,如果查询 \(q\) 次,那么暴力查询的复杂度为 \(O\left(nmq\right)\) ,而用二维前缀和则只需要 \(O\left(q\right)\) ,可见是不小的优化。
实现过程
预处理
实现这个算法需要先预处理一个二维数组 \(S\),存放这个矩阵从 \(0,0\) 到 \(i,j\) 的子矩阵元素的和 \(\left(1\leq i\leq n,1\leq j \leq m\right)\) 。
这样子不好理解,我举一个例子:
在 \(3\times 3\) 的矩阵中,\(S_{2,2}\) 就指的是下图红色块的和:
那么,如何预处理矩阵呢?
参照上图矩阵,求 \(S_{2,2}\) ,就需要用 \(2\) 和 \(4\) \(\left( S_{2,1}\right)\) 加上 \(2\) 和 \(3\) \(\left(S_{1,2}\right)\) ,这样 \(2\) \(\left(S_{1,1}\right)\) 被加了两次,需要减去。这样就可以根据已知推出整个 \(S\) 矩阵了。
递推式: \[ S_{i,j}=S_{i-1,j}+ S_{i,j-1}-S_{i-1,j-1}+a_{i,j} \]
计算
给出的样例可不一定是左下角是 \(1,1\) 的矩阵。 比如求下图绿色部分的和,就要用 \(S_{3,3}\) 减去粉色部分的和。
现在的问题就是粉色部分怎么求。
把粉色部分分成两部分,一个是 \(S_{3,1}\) ,另一个是 \(S_{1,3}\) 。把它们加起来,就多了一个 \(S_{1,1}\) 在把它减去就可以了。
假设子矩阵左上角是 \(\left(x1,y1\right)\) ,右上角是 \(\left(x2,y2\right)\) ,那么矩阵的和为: \[ S_{x2,y2}-S_{\left(x1-1\right),y2}-S_{x2,\left(y1-1\right)}+S_{\left(x1-1\right),\left(y1-1\right)} \]
例题及讲解
直链
思路
模板题,就是求矩阵元素和,直接套公式,计算出来即可。
千万不要用暴力,复杂度会达到 \(O\left(2\times 10^{11}\right)\) ,小心TLE
Code
1 |
|