开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第24天,点击查看活动详情
前缀和
一维前缀和
前缀和的作用:
为了更快,可以多次查找一个区间的累加和,例如:要求[left,right]区间的和,如果没有前缀和,就需要遍历数组求和,时间复杂度O(N), 如果有前缀和:时间复杂度是O(1)
S[i] = a[0] + a[1] + ... + a[i]
如何构造一维前缀和数组呢
前缀和数组的表达式:presum[i] = presum[i-1] + arr[i] ,其中preSum[0] = a[0]
例子:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n,m;
cin >> n >> m;
vector<int> a(n+1,0);
vector<int> s(n+1,0);
for(int i = 1 ; i <= n ;++i) cin >> a[i];
//构造前缀和数组
s[0] = a[0];
for(int i = 1 ; i <= n ;++i) s[i] = s[i-1]+a[i];
while(m--) //m次询问
{
int l,r;
cin >> l >> r; //求[left,right]区间元素的和
if(l == 0)
cout << s[r] << endl;
else
cout << s[r] - s[l-1] << endl;
}
return 0;
}
二维前缀和
假设:S[i, j] 表示的是第i行j列格子左上部分所有元素的和, 如果想求以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵的和为 S
S = S[x2, y2] - S[x1 - 1, y2] - S[x2, y1 - 1] + S[x1 - 1, y1 - 1]
如何求构造二维前缀和数组呢
s[i][j] = s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j] //s[i][j]是i行j列及其左上方所有元素的累加和
例子
#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 -- ) //进行q次询问
{
int x1, y1, x2, y2; //求(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;
}