题目描述
输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数x1, y1, x2, y2,表示一个子矩阵的左上角坐标和右下角坐标。
对于每个询问输出子矩阵中所有数的和。
输入格式
第一行包含三个整数n,m,q。
接下来n行,每行包含m个整数,表示整数矩阵。
接下来q行,每行包含四个整数x1, y1, x2, y2,表示一组询问。
输出格式
共q行,每行输出一个询问的结果。
数据范围
$1≤n,m≤1000$
$1≤q≤200000$
$1≤x1≤x2≤n$
$1≤y1≤y2≤m$
−1000≤矩阵内元素的值≤1000
输入样例:
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
输出样例:
17
27
21
思路
(注:下文中所提到的“面积”所指的是当前矩阵所有格子的数值之和)
我们定义一个a数组和s数组(当然也可以只定义s数组,就可以直接输入到s数组里,在进行存储的时候直接+=就行了)
输入a数组里的每一个数
在进行计算之前,我们先要把s数组里的每一个数定义好
s数组里的每一个数都表示从(1,1)到(i,j)的子矩阵的和
我们要求的就是红色部分矩阵的面积,即s[i][j]
想要求这部分面积我们就要先加上绿色部分的面积,即s[i][j-1]
然后再加上黄色部分的面积,即s[i-1][j]
我们可以发现绿色部分和黄色部分有一部分是重叠的,就是紫色的部分,即s[i-1][j-1]
因为重叠了,所以紫色的部分加了两遍
我们只想加一遍
所以要减一遍
然后我们在加上(i,j)这个点本身的值就行了
由此我们可以推出:从s[i][j]
就是先加上s[i][j-1]
,再加上s[i-1][j]
,再减去s[i-1][j-1]
用公式表示为:s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]
用公式表示为:s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]
我们定义一个数组s,每个格子都代表了一个子矩阵的和,s[i,j]就是从(1,1)到)(i,j)的所有子矩阵的和
比如我们现在要求从(x1,y1)到(x2,y2)的子矩阵的和
我们要求红色的部分,红色的部分就是从(x1,y1)到(x2,y2)的子矩阵的和
现在,我们要用整个s[x2][y2]
的面积把绿色的部分减掉,即s[x2][y1-1]
然后再将黄色的部分减掉,即s[x1-1][y2]
我们会发现绿色的部分和黄色的部分有一部分是重叠的,就是图中紫色的部分,即s[x1-1][y1-1]
因为重叠了,所以这部分减了两次
我们只希望减掉一次
所以我们要再加上一次
由此我们可以推出:从(x1,y1)到(x2,y2)的子矩阵的和就是把整个s[x2][y2]
的面积减去s[x2][y1-1]
,再减去s[x1-1][y2]
,然后再加上s[x1-1][y1-1]
用公式表示为:s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]
代码
写法一
#include<iostream>
using namespace std;
int s[1010][1010];
int n,m,q;
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>s[i][j];
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
int x1,y1,x2,y2;
while(q--)
{
cin>>x1>>y1>>x2>>y2;
int p=s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
cout<<p<<endl;
}
return 0;
}
写法二
#include<iostream>
using namespace std;
int s[1010][1010];
int a[1010][1010];
int n,m,q;
int main()
{
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>a[i][j];
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
}
}
int x1,y1,x2,y2;
while(q--)
{
cin>>x1>>y1>>x2>>y2;
int p=s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
cout<<p<<endl;
}
return 0;
}
附:二维前缀和 —— 模板题 AcWing 796. 子矩阵的和
S[i, j] = 第i行j列格子左上部分所有元素的和
以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为:
S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]