一维二维前缀和详解
作者:互联网
一、一维前缀和
1.前缀和是啥
前缀和其实就是用一个数组S存下数组a的前缀的和,这样话方便以后的查找,提高查找的速度。
2.一维前缀的时间复杂度
因为是遍历一遍数组a就可以得到我们的前缀和数组,所以前缀和的时间复杂度是O(n)。
如果是m次查找的话,我们就可以做到O(n+m)的时间复杂度。
3.一维前缀和公式的推导
一维的前缀和比较简单,这样的话我们先推导一下一维的前缀和的公式。
为了方便的话,我们一般在用前缀和的时候数组从下标为1的地方开始读入。这样是为了防止数组越界,我们可以这样考虑,当前我们已经该算下标为i的前缀和,因此我们这时肯定已经算过了下标为i-1的前缀和,这是我们这时只需要用下标为i-1的前缀和加上当前的下标为i的那个值,是不是就可以得到下标为i的前缀和。
于是我们可以很容易的得到一维前缀和的公式$$S[i]=S[i-1]+a[i]$$
for(int i = 1; i <= n; i ++)
s[i] = S[i - 1] + a[i[]];
通过这样的一段代码就可以求出a数组的前缀和数组S,那我们知道了这个概念的话怎么用呢,我们接下来就看一道例题
4.一维前缀和的例题
AcWing前缀和例题
思路:就是一个非常裸的前缀和,然后进行m次查询即可,如果我们每次都进行遍历求和的话就会超时。
参考代码
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N],S[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) S[i]=S[i-1]+a[i];
while(m--)
{
int l,r;
cin>>l>>r;
cout<<S[r]-S[l-1]<<endl;
}
return 0;
}
二、二维前缀和
1.二维前缀和的时间复杂度
二维前缀和的时间复杂度其实可以类比一维的时间复杂度,就是把这个二维数组遍历一遍,这样的话就是O(n*m)的时间复杂度
2.二维前缀和公式的推导
二维的前缀和就比一维的麻烦一些,我们没办法直接求出我们需要的所以我们只能先算出一个然后再减去重复的部分,最后我们可以得到$$s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+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];
3.二维前缀和的子矩阵的查询
子矩阵也不是直接就可以查出来我们也只能用公式进行计算和上面求前缀和的过程差不多$$s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]$$
4.二维前缀和的例题
AcWing二维前缀和的例题
思路:就是简单的二维前缀和,正常的直接加的话会超时
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int a[N][N], s[N][N];
int main()
{
int n, m, q;
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
scanf("%d", &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 (q--)
{
int x1, x2, y1, 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;
}
标签:前缀,int,复杂度,二维,详解,一维,例题 来源: https://www.cnblogs.com/byAttention/p/16685257.html