子矩阵的和

Solution:

#include <iostream>
#include <vector>
using namespace std;

int main() {
int n, m, q;
cin >> n >> m >> q;
vector<vector<int>> matrix(n + 1, vector<int>(m + 1, 0));  // 整数矩阵

// 输入整数矩阵
for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
        cin >> matrix[i][j];
    }
}

// 计算前缀和
vector<vector<int>> prefixSum(n + 1, vector<int>(m + 1, 0));
for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
        prefixSum[i][j] = prefixSum[i - 1][j] + prefixSum[i][j - 1] - prefixSum[i - 1][j - 1] + matrix[i][j];
    }
}

// 处理询问
while (q--) {
    int x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;

    int result = prefixSum[x2][y2] - prefixSum[x2][y1 - 1] - prefixSum[x1 - 1][y2] + prefixSum[x1 - 1][y1 - 1];
    cout << result << endl;
}

return 0;}

在上一篇的文章中,我们已经介绍了前缀和。

这次的题目就是利用前缀和思想来优化计算子矩阵和的过程。

  1. 先输入整数矩阵,将其保存在一个二维矩阵 matrix 中。
  2. 计算 matrix 的前缀和矩阵 prefixSum,其中 prefixSum[i][j] 表示矩阵中 (1,1) 到 (i,j) 所有元素的和。
  3. 对于每个询问,计算出其子矩阵中所有元素的和。具体做法是,用前缀和矩阵计算出子矩阵的四个角的前缀和,然后利用前缀和的性质计算出子矩阵中所有元素的和。

其中,核心思想:

在计算前缀和矩阵时,可以使用类似于一维前缀和的方式,具体计算公式如下:

其中,prefixSum[i][j] 表示矩阵中 (1,1) 到 (i,j) 所有元素的和,matrix[i][j] 表示矩阵中第 i 行第 j 列的元素。

对于每个询问,我们读取左上角坐标 (x1, y1) 和右下角坐标 (x2, y2),然后使用前缀和数组 prefixSum 计算子矩阵中所有数的和:

最后,输出结果 result

Q:为什么能这样计算前缀和呢?

可能有很多朋友到这感觉稍微抽象,不能直接的理解。

假设我们有以下 3x3 的整数矩阵:

1 2 3
4 5 6
7 8 9

首先,我们构建一个与输入矩阵大小相同的前缀和数组 prefixSum

0 0 0 0
0 1 3 6
0 5 12 21
0 12 27 45

prefixSum 中的每个元素 prefixSum[i][j] 表示原矩阵中从 (1, 1) 到 (i, j) 的子矩阵的和。

例如,prefixSum[2][2] 表示原矩阵中从 (1, 1) 到 (2, 2) 的子矩阵的和,即 1 + 2 + 4 + 5 = 12

现在,我们可以使用前缀和数组 prefixSum 来计算任意子矩阵的和。

假设我们想计算从 (1, 1) 到 (2, 3) 的子矩阵的和,即矩阵中的所有元素的和。我们可以使用前缀和数组的性质来计算:

那么

result = prefixSum[2][3] - prefixSum[2][0] - prefixSum[0][3] + prefixSum[0][0]
       = 21 - 0 - 0 + 0
       = 21

因此,从 (1, 1) 到 (2, 3) 的子矩阵的和为 21。

通过构建和利用前缀和数组,我们可以在常数时间复杂度内计算任意子矩阵的和,而不需要每次都重新遍历矩阵。这在处理大型矩阵和多个询问时非常高效。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值