什么是前缀和
前缀和(Prefix Sum)的定义为:对于一个给定的数列 A, 它的前缀和数列 S 是通过递推能求出来得
部分和。
例如:
![A[5, 6, 7, 8] = PrefixSum[5, 11, 18, 26]\\ PrefixSum[0] = A[0]\\ PrefixSum[1] = A[0] + A[1]\\ PrefixSum[2] = A[0] + A[1] + A[2]\\ PrefixSum[3] = A[0] + A[1] + A[2] + A[3]\\ ...\\ PrefixSum[n] = A[0] + A[1] + A[2] + A[3] + ... + A[n]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
C++实现
//假设数组a和前缀和数组s都已经定义 int i; //初始条件 a[0] = 0; s[0] = 0; for (i=1; i<=n; i++) { cin >> a[i]; s[i] = s[i-1] + a[i]; }
模板题
下面我们用一个模板题,将完整的一维数组前缀和做一个简单的展示。题目链接http://47.110.135.197/problem.php?id=5181。
#include
using namespace std; int main() { int n; cin >> n; int data; int ans[102] = {}; for (int i=1; i<=n; i++) { cin >> data; ans[i] = ans[i-1] + data; } for (int i=1; i<=n; i++) { cout << ans[i] << " "; } cout << endl; return 0; }
用途
前缀和是一种重要的预处理,能大大降低查询的时间复杂度。
前缀和是以求和的方式灵活地面对区间询问。
下面我们用一个模板题来说明。
例题:区间求和
给你一串长度为 n 的数列 a1, a2, a3, …, an,再给出 m 个询问,每次询问给出 L, R 两个数,要求给出区间 [L, R] 里的数的和。
详细可以参看http://47.110.135.197/problem.php?id=5139。
题目分析
题目非常简单,我们也可以得到一个最简单的解法,暴力操作。也就是对应每个询问,我们都从 L 开始到 R 结束对这个区间的数据进行求和。基本的代码如下:
#include
using namespace std; const int MAXN = 1e5+2; long long arr[MAXN] = {}; int main() { int n; cin >> n; int i, j; for (i=1; i<=n; i++) { cin >> arr[i]; } int m; int l, r; long long ans = 0; cin >> m; for (i=0; i
> l >> r; ans = 0; for (j=l; j<=r; j++) { ans += arr[j]; } cout << ans << endl; } return 0; }
代码分析
从上面的代码非常明确的分析出来,代码的时间复杂度为
。也就是说,在比赛中这样的解法能否 AC,那就要看数据的量了。当然我们都知道这样的解法,比赛中是肯定不可能 AC。因此唯一的可能就是降低时间复杂度。方法就是使用前缀和。
我们先看前缀和的数学。数列A中某个下标区间 [l, r] 内的数的和定义为:
![sum[l, r] = \sum_{i = l}^{r}A[i]\\ = a[l] + a[l+1] + \cdots + a[r]\\ = S[r] - S[l-1]](https://javaforall.net/wp-content/uploads/2020/11/2020110817443450.jpg)
从上面推导,我们可以清晰的看出,前缀和和区间和的关系。
代码改进
#include
using namespace std; const int MAXN = 1e5+2; long long arr[MAXN] = {}; long long sum[MAXN] = {}; int main() { int n; cin >> n; int i, j; for (i=1; i<=n; i++) { cin >> arr[i]; sum[i] = sum[i-1] + arr[i]; } int m; int l, r; cin >> m; for (i=0; i
> l >> r; cout << sum[r] - sum[l-1] << endl; } return 0; }
代码分析
从上面的代码非常明确的分析出来,代码的时间复杂度为
。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229738.html原文链接:https://javaforall.net
