子矩阵的和(二维前缀和)

一、算法描述

上一篇文章介绍了一维前缀和,也就是一个数组的前n项和,这篇文章来介绍一下什么是二维前缀和。

含义

  • 一维的是前n项的和,那么二维的情况下,表示的则是与左上角形成的矩形和。

怎么求

  • 一维的递推关系式是s[i] = s[i - 1] + a[i];,我们根据含义来思考二维的递推关系式,读者可以在草稿纸上画一个矩形来更好的理解。

  • s[i][j] 表示的是 i,j 这个位置与左上角形成的矩形和,s[i1][j] 表示的是比 s[i][j] 少一行的矩形和, s[i][j1] 表示的是比 s[i][j] 少一列的矩形和。

  • s[i1][j]+s[i][j1] 得到的就是 s[i][j] ,但是少了一个 a[i][j] ,同时多了一个 i1,j1 与左上角形成的矩形和,即 s[i1][j1]

  • 综上可以得到求得 s[i][j] 的递推关系式为:s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];,读者应在草稿纸上自己推理,不要纯靠记忆。

怎么用

  • 一维前缀和的用法在 O(1) 的时间复杂度内求得 [l,r] 的区间和,那么二维前缀和则是在 O(1)的时间复杂度内求得 [x1,y1][x2,y2]这个区域的矩形和。

  • 显然我们要用 s[i][j] 这块大面积来减去其他的面积,那么需要减去哪些部分呢?大家自行在草稿纸上推演,计算如下:s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1];,根据含义来思考如何推算。

二、题目描述

输入一个 nm 列的整数矩阵,再输入 q 个询问,每个询问包含四个整数 x1,y1,x2,y2,表示一个子矩阵的左上角坐标和右下角坐标。

对于每个询问输出子矩阵中所有数的和。

输入格式

第一行包含三个整数 nmq

接下来 n 行,每行包含 m 个整数,表示整数矩阵。

接下来 q 行,每行包含四个整数 x1,y1,x2,y2,表示一组询问。

输出格式

q 行,每行输出一个询问的结果。

数据范围

1n,m1000,
1q200000,
1x1x2n,
1y1y2m,
10001000

输入样例:

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 

三、题目来源

AcWing算法基础课-796.子矩阵的和

四、源代码

#include <iostream>

using namespace std;

const int N = 1010;

int n, m, q;
int a[N][N], s[N][N];

int main()
{
    cin >> n >> m >> q;
    
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cin >> a[i][j];
        
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + a[i][j];
            
    while (q -- )
    {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        
        cout << s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1] << endl;
    }
    
    return 0;
}
posted @   grave-master  阅读(186)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示