前缀和
前缀和数组s[ ],数组a[ ]的前n项和。
如何求前缀和数组s[ ]?
核心公式:s[i] = s[i - 1] + a[i]
作用:用于快速求出数组内一段区间[l,r]的和。如果不使用前缀和而朴素的扫描一遍,时间复杂度位O(n)。通过前缀和时间复杂度为O(1)。
区间[l,r]的和:s[r] - s[l - 1]
注意:前缀和数组的下标从1开始,并且定义S[0] = 0。这是为了公式的统一。
795 前缀和
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100010;
int n,m;
int a[N],s[N];
int main()
{
cin>>n>>m;
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(m--)
{
int l = 0,r = 0;
cin>>l>>r;
cout<<s[r]-s[l-1]<<endl;
}
return 0;
}
二维前缀和
类似上面的一维前缀和,我们有二维数组a[ ][ ]以及二位前缀和数组s[ ][ ].
如何构建二维前缀和数组呢?
核心公式: s[x][y] = s[x-1][y] + s[x][y-1] - s[x - 1][y - 1] + a[x][y]
作用:快速求出二维数组内区间[x2,y2]到[x1,y1]和。
区间[x2,y2]到[x1,y1]的和: s[x2][y2] - s[x2][y1-1] + s[x1 - 1][y2] + s[x1 - 1][y1 - 1]
796 子矩阵的和
代码
#include<iostream>
#include<cstdio>
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-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
while(m--)
{
int x1 = 0,y1 = 0,x2 = 0, y2 = 0;
cin>>x1>>y1>>x2>>y2;
cout<<s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]<<endl;
}
return 0;
}