前缀和
682 字
3 分钟
前缀和

前缀和
前缀和用来快速求区间和。它的核心是提前做一次预处理,把“每次都遍历区间”变成“两个数组值相减”。
1、为什么需要前缀和
假设有数组:
1 2 3 4 5如果想求 [2, 4] 的和,也就是:
2 + 3 + 4 = 9普通做法是每次循环一遍区间,复杂度是 O(n)。
如果有很多次查询,这样会很慢。前缀和可以把每次查询降到 O(1)。
2、一维前缀和公式
定义:
s[i] = a[1] + a[2] + ... + a[i]那么:
s[i] = s[i - 1] + a[i]查询 [l, r] 的区间和:
a[l] + ... + a[r] = s[r] - s[l - 1]3、一维前缀和模板
#include <bits/stdc++.h>using namespace std;
const int N = 100010;
int n, m;int a[N], s[N];
int main() { scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1; i <= n; i++) { s[i] = s[i - 1] + a[i]; }
while (m--) { int l, r; scanf("%d%d", &l, &r); printf("%d\n", s[r] - s[l - 1]); }
return 0;}这里建议数组从 1 开始存,这样 s[l - 1] 更自然。
4、二维前缀和解决什么问题
二维前缀和用于快速求一个子矩阵的和。
比如矩阵里要查询左上角 (x1, y1) 到右下角 (x2, y2) 这个矩形区域的总和。
5、二维前缀和公式
构造公式:
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]查询公式:
sum = s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]可以理解为:先取大矩形,再减掉上面和左边多算的部分,最后把左上角被减了两次的区域加回来。
6、二维前缀和模板
#include <bits/stdc++.h>using namespace std;
const int N = 1010;
int n, m, q;int a[N][N], 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", &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, 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;}7、容易写错的地方
(1)二维构造时循环边界写错
for (int j = 1; j <= m; j++)不要写成 j < m,否则最后一列不会被处理。
(2)查询循环变量写错
二维前缀和通常有 q 次查询:
while (q--)不要误写成 while (m--)。
(3)查询公式下标写混
记住是:
右下 - 上方 - 左方 + 左上总结
前缀和适合“多次区间求和”。一维记住:
s[r] - s[l - 1]二维记住:
大矩形 - 上面 - 左边 + 左上角文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














