前缀和数组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; }