【前缀和】二维前缀和(模板题)

在这里插入图片描述

DP35 【模板】二维前缀和

DP35 【模板】二维前缀和

​ 给你一个 nm 列的矩阵 A ,下标从 1 开始,接下来有 q 次查询,每次查询输入 4 个参数 x1 , y1 , x2 , y2

​ 请输出以 (x1, y1) 为左上角,(x2,y2) 为右下角的子矩阵的和。

输入描述:

​ 第一行包含三个整数 nmq

​ 接下来 n 行,每行 m 个整数,代表矩阵的元素

​ 接下来 q 行,每行 4 个整数 x1y1x2y2,分别代表这次查询的参数。

在这里插入图片描述

输出描述:

​ 输出 q 行,每行代表一次查询的结果。

示例1:

输入:
    3 4 3
    1 2 3 4
    3 2 1 0
    1 5 7 8
    1 1 2 2
    1 1 3 3
    1 2 3 4
输出:
    8
    25
    32

解题思路

​ 一开始我有一个思路,虽然时间复杂度不是很好,其实就是借用了一维前缀和的思路,先开辟一个二维数组 prefix,然后将二维数组的每一行都进行一维前缀和,接着在多次查询中就需要遍历多列去获取每行的前缀和,累加起来,得到最后的前缀和!

​ 虽然这种做法是可以的,但其实时间复杂度没有达到最优处理!所以我们要利用二维前缀和的思想,其实就是一个简单的二维动态规划问题!

​ 那么我们就得想办法看看建立起一个状态转移方程,如下图所示,红色区域是我们要求的元素:
在这里插入图片描述

​ 此时如果我们直接从 [x1, y1] 开始求的话,那是比较麻烦的,和我们上面那个思路是差不多的,所以我们不妨这样子想:我们要求的区间,其实可以将其从 [1, 1][x2, y2] 区间分为下面四个区域:

在这里插入图片描述

​ 那我们想,能不能就求

C++中,我们可以使用模板来创建一个通用的二维数组(如矩阵)的前缀和结构。前缀和是一种数据结构,用于快速查询数组元素之和,特别是对于区间和的问题。以下是一个简单的模板示例,用于计算二维数组每个子区域的累加和: ```cpp template <typename T> class TwoDimensionalPrefixSum { private: std::vector<std::vector<T>> prefixSum; // 二维前缀和数组 public: // 构造函数,初始化所有元素为0 TwoDimensionalPrefixSum(std::vector<std::vector<T>>& matrix) : prefixSum(matrix.size()) { for (std::size_t i = 0; i < matrix.size(); ++i) { prefixSum[i].resize(matrix[i].size()); for (std::size_t j = 0; j < matrix[i].size(); ++j) { if (i == 0 && j == 0) { prefixSum[i][j] = matrix[i][j]; } else { prefixSum[i][j] = matrix[i][j] + prefixSum[i - 1][j - 1]; } } } } // 获取指定范围的累加和 T getSum(std::size_t rowStart, std::size_t colStart, std::size_t rowEnd, std::size_t colEnd) const { if (rowStart > rowEnd || colStart > colEnd) return 0; return prefixSum[rowEnd][colEnd] - (rowStart > 0 ? prefixSum[rowStart - 1][colEnd] : 0) - (colStart > 0 ? prefixSum[rowEnd][colStart - 1] : 0) + (rowStart > 0 && colStart > 0 ? prefixSum[rowStart - 1][colStart - 1] : 0); } }; // 使用示例 int main() { std::vector<std::vector<int>> matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; TwoDimensionalPrefixSum<int> sumMatrix(matrix); int sum1 = sumMatrix.getSum(0, 0, 2, 2); // 返回15(1+2+3) int sum2 = sumMatrix.getSum(1, 1, 2, 2); // 返回10(4+5) return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

利刃大大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值