一、前缀和基本介绍
前缀和分为一维前缀和和二维前缀和。一维前缀和用于求前n项得和,或者是求一个区间内的数之和,如果采用简单的遍历,时间复杂度将是 O ( n ) O(n) O(n),若采用前缀和的方法则是 O ( 1 ) O(1) O(1)的复杂度。二维前缀和是一维前缀和的扩展,可以理解维求方格的面积,具体看第二部分。
1、一维前缀和
一维前缀和比较简单用于求前n项和或某个区间内的数之和,用公式描述如下:
1.s[0]=0
2.s[i] = s[i-1]+a[i]
数组a是一维数的序列,s[i]用于记录前i项的和,s[0]初始化为0。
习题链接AcWing795.前缀和
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 1e5+10;
int a[N],s[N];
/*
一维前缀和
1、求
S[0] = 0
S[i] = a[i]+S[i-1]
2、计算
前5到前7个
S[7]-S[5]
二维前缀和
*/
int main()
{
int n,k;
cin>>n>>k;
for(int i =1;i<=n;++i)
cin>>a[i];
s[0] = 0;
for(int i =1;i<=n;i++)
s[i] = s[i-1]+a[i];
while (k--)
{
int l,r;
cin>>l>>r;
cout<<s[r]-s[l-1]<<endl;
}
system("pause");
return 0;
}
2、二维前缀和
二维前缀和用于求二维矩阵中某子矩阵的数之和,例如求下图中绿色子矩阵内所有的数之和,那我们应该如何去求解呢?类比一维前缀和,假设我们已经知道红色子矩阵数之和,蓝色子矩阵数之和,粉色子矩阵中的数之和,分别是 S [ x 2 ] [ y 2 ] 、 S [ x 1 − 1 ] [ y 2 ] 、 S [ x 2 ] [ y 1 − 1 ] S[x2][y2]、S[x1-1][y2]、S[x2][y1-1] S[x2][y2]、S[x1−1][y2]、S[x2][y1−1],绿色区域的前缀和可以用如下式子表示:
S
[
x
2
]
[
y
2
]
−
S
[
x
1
−
1
]
[
y
2
]
−
S
[
x
2
]
[
y
1
−
1
]
+
S
[
x
1
]
[
y
1
]
S[x2][y2] - S[x1-1][y2] - S[x2][y1-1] + S[x1][y1]
S[x2][y2]−S[x1−1][y2]−S[x2][y1−1]+S[x1][y1]
上式就是求二维矩阵中子矩阵的前缀和公式。
我们已经知道了如何求解二维矩阵中子矩阵内所有数之和,那么该如何构建矩阵S呢?具体构建方法如下,我们假设绿色区域内的任意子矩阵内数之和已知,接下来求(i,j)红色子矩阵中的数之和,即S[i][j],从下图中我们不难看出其求法:
S
[
i
]
[
j
]
=
a
[
i
]
[
j
]
+
S
[
i
]
[
j
−
1
]
+
S
[
i
−
1
]
[
j
]
−
S
[
i
−
1
]
[
j
−
1
]
S[i][j] = a[i][j] + S[i][j-1] + S[i-1][j] - S[i-1][j-1]
S[i][j]=a[i][j]+S[i][j−1]+S[i−1][j]−S[i−1][j−1]
用文字来描述就是,红色子矩阵的数之和 =a[i][j]元素 + 蓝色子矩阵数之和 + 粉色子矩阵数之和 - 蓝色子矩阵和粉色子矩阵重复的内容(因为重复加了)
习题链接AcWing796 子矩阵的和
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1010;
int a[N][N],s[N][N];
/*
二维前缀和
1、求
初始化
S[i,j] = a[i,j] + S[i-1,j]+s[i,j-1] + s[i-1,j-1]
2、计算
左上角(x1,y1) 右下角(x2,y2)
S[x2,y2] - s[x2,y1-1]-s[x1-1,y2] + S[x1-1,y1-1]
*/
int main()
{
int n,m,k;
cin>>n>>m>>k;
//memset(s,0,sizeof(s));
for(int i =1;i<=n;++i)
{
for(int j =1;j<=m;++j)
{
cin>>a[i][j];
s[i][j] = a[i][j] +s[i][j-1]+s[i-1][j]-s[i-1][j-1];
}
}
while (k--)
{
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
int num = s[x2][y2] - s[x2][y1-1]-s[x1-1][y2] + s[x1-1][y1-1];
cout<<num<<endl;
}
system("pause");
return 0;
}