AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 796. 子矩阵的和 【 c++详细题解 】    原题链接    简单

作者: 作者的头像   林小鹿 ,  2020-12-19 20:58:37 ,  所有人可见 ,  阅读 10954


163


88

二维前缀和推导

如图:

20201217174700577.png{:width=”50%”}

紫色面积是指(1,1)左上角到(i,j-1)右下角的矩形面积, 绿色面积是指(1,1)左上角到(i-1, j )右下角的矩形面积。每一个颜色的矩形面积都代表了它所包围元素的和。
20201216215336857.png
从图中我们很容易看出,整个外围蓝色矩形面积s[i][j] = 绿色面积s[i-1][j] + 紫色面积s[i][j-1] - 重复加的红色的面积s[i-1][j-1]+小方块的面积a[i][j];

因此得出二维前缀和预处理公式

s[i] [j] = s[i-1][j] + s[i][j-1 ] + a[i] [j] - s[i-1][ j-1]

接下来回归问题去求以(x1,y1)为左上角和以(x2,y2)为右下角的矩阵的元素的和。

如图:
2020121717473287.png{:width=”50%”}

紫色面积是指 ( 1,1 )左上角到(x1-1,y2)右下角的矩形面积 ,黄色面积是指(1,1)左上角到(x2,y1-1)右下角的矩形面积;

不难推出:
20201217170800381.png

绿色矩形的面积 = 整个外围面积s[x2, y2] - 黄色面积s[x2, y1 - 1] - 紫色面积s[x1 - 1, y2] + 重复减去的红色面积 s[x1 - 1, y1 - 1]

因此二维前缀和的结论为:

以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
s[x2, y2] - s[x1 - 1, y2] - s[x2, y1 - 1] + s[x1 - 1, y1 - 1]

总结:

20201217174751639.png

代码:

#include <iostream>

using namespace std;

const int N = 1010;

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

int main()
{
    scanf("%d%d%d", &n, &m, &q);

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            scanf("%d", &s[i][j]);

    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= m; j ++ )
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];

    while (q -- )
    {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n", s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
    }

    return 0;
}

44 评论


用户头像
学不会动态规划不改名   2023-01-08 16:18      2    踩      回复

博主为什么用cin和cout写会爆栈呢

用户头像
yago   2023-01-15 13:39      7    踩      回复

简单来讲scanf 和 cin 在时间效率上差别很大的原因是:
在scanf元素的类型我们已经告知了,机器不用再去查找元素类型,scanf需要自己写格式,是一种格式化输入。
而在cin 元素类型由机器自己查找,cin是字符流输入,需要先存入缓冲区再输入。


用户头像
xyj23   2022-07-19 20:06      2    踩      回复

咋还是错的…大佬们帮忙看看啊

#include<iostream>
#include<cstdio>
using namespace std;
int a[1001][1001],x1[200010],y1[200010],x2[200010],y2[200010],d[1001][1001];
int main()
{
    int n,m,q;
    cin>>n>>m>>q;
    for(int i = 0;i < n;i ++){
        for(int j = 0;j < m;j ++){
            cin>>a[i][j];d[i][j]=d[i-1][j]+d[i][j-1]-d[i-1][j-1]+a[i][j];
        }
    }

    for(int i = 0;i < q;i ++)
    {
        cin>>x1[i]>>y1[i]>>x2[i]>>y2[i];
        cout<<d[x2[i]-1][y2[i]-1]+d[x1[i]-2][y1[i]-2]-d[x1[i]-2][y2[i]-1]-d[x2[i]-1][y1[i]-2]<<endl;
    }
    return 0;
}
用户头像
呆瓜杰   2022-11-29 19:57      2    踩      回复

下标从1开始最好,你让i=1,j=1然后到n就好了,不然会有边界问题,从零开始和矩阵对应不上

用户头像
TUNAN1121   8个月前         踩      回复

下标从0开始最后会减到-1,导致数组越界。


用户头像
早睡早起有益健康   2021-08-11 00:01      1    踩      回复

s[x2, y2] - s[x1, y2] - s[x2, y1] + s[x1 , y1] 请问求子矩阵的和不能这样计算吗

用户头像
Ran_   2021-11-03 11:19         踩      回复

不行,因为这样就会把边界的值漏掉,建议自己把两个矩阵都画出来然后再来看,就会清晰很多

用户头像
itboy   2022-04-06 12:06      2    踩      回复

可以类比一维的前缀和,求i到j之间的和为s[j]-[i-1];
s数组是包含下标的数的,而我们要求的是下标之间的和(包括下标)

用户头像
眼镜蛇   2022-08-07 15:04    回复了 Ran_ 的评论         踩      回复

不是漏掉,而是不能不能多减去“自己”。


用户头像
œ   8个月前         踩      回复

orz


用户头像
The_Second_Coming   2023-08-06 09:24         踩      回复

66666


用户头像
-_421   2023-08-04 20:11         踩      回复

tql


用户头像
acwing_83420   2023-08-04 17:15         踩      回复

orz


用户头像
GainCompiler   2023-03-22 16:33         踩      回复

大佬 图片挂掉了


用户头像
Pobz   2023-01-06 08:52         踩      回复

太强了


用户头像
末流211选手   2023-01-04 16:12         踩      回复

会有segment错误


用户头像
SHIDA   2022-11-08 23:02         踩      回复

%%%


用户头像
5716   2022-05-05 11:30         踩      回复

赞


用户头像
下栈   2022-04-11 21:55         踩      回复

妙妙秒


用户头像
小黑不开心   2022-03-27 16:33         踩      回复

orz


用户头像
晒干了沉默   2022-03-10 13:38         踩      回复

为什么用cout会爆了

用户头像
yago   2023-01-15 13:38      2    踩      回复

简单来讲scanf 和 cin 在时间效率上差别很大的原因是:
在scanf元素的类型我们已经告知了,机器不用再去查找元素类型,scanf需要自己写格式,是一种格式化输入。
而在cin 元素类型由机器自己查找,cin是字符流输入,需要先存入缓冲区再输入。


用户头像
exile_0   2022-02-11 16:49         踩      回复

太厉害了!


用户头像
@简单   2022-02-06 10:10         踩      回复

yyds!!!!!


用户头像
捧星   2021-12-25 21:12         踩      回复

66666很厉害!!


用户头像
DracoMalfoy   2021-07-28 15:52         踩      回复

还是没懂为啥求部分和的公式要写成y1-1,x1-1什么的

用户头像
DracoMalfoy   2021-07-28 15:55         踩      回复

懂了懂了哈哈


用户头像
xyu   2021-07-14 15:30         踩      回复

一下子就弄懂了

用户头像
考拉考拉   2022-07-11 20:49         踩      回复

能给我解释下吗,x1为啥要减1

用户头像
mzmzrw   2022-08-31 13:35    回复了 考拉考拉 的评论      1    踩      回复

想成只有点有值试试(代码中矩阵赋值也是给点的),既然以x1,y1为左上角,自然是包含x1,y1了,你要不减去1,就会把x1,y1也给减去


你确定删除吗?
1024
x

© 2018-2024 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息