5.前缀和
核心思想
通过预处理生成前缀和数组,将 "区间和查询" 从 O (n) 优化为 O (1),适用于多次查询的场景。
1. 一维前缀和
定义
- 原数组
a[1..n](下标从 1 开始),前缀和数组s[1..n],其中s[i] = a[1] + a[2] + ... + a[i]; - 区间和公式:
sum(l..r) = s[r] - s[l-1](下标从 1 开始,避免l=1时l-1=0的边界问题)。
代码模板(含应用)
C++
#include <cstdio>
using namespace std;
const int N = 1e5 + 10;
int a[N], s[N];
int main()
{
int n, m;// n个数,处理m次查询
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;
}
测试案例
- 输入:n=5,a=[1,2,3,4,5],m=2,查询 (1,3)、(2,5)
- 预处理:s=[0,1,3,6,10,15]
- 查询结果:6-0=6(1+2+3),15-1=14(2+3+4+5)
- 输出:6、14
2. 二维前缀和(子矩阵和)
定义
- 原矩阵
a[1..n][1..m](下标从 1 开始),前缀和矩阵s[1..n][1..m],其中s[x][y]表示左上角 (1,1) 到右下角 (x,y) 的子矩阵和; - 预处理公式:s[x][y] = s[x-1][y] + s[x][y-1] - s[x-1][y-1] + a[x][y](避免重复计算重叠区域);
- 子矩阵和公式:sum(x1,y1,x2,y2) = s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1]。

代码模板(含应用)
C++
#include <cstdio>
using namespace std;
const int N = 1e3 + 10;
int s[N][N]; // 直接用s存储原矩阵+前缀和(节省空间)
int main()
{
int n, m, q;
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]);
s[i][j] += s[i-1][j] + s[i][j-1] - s[i-1][j-1];//求前缀和
}
}
// 处理q次查询
while (q--)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
int res = s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1];//算矩阵和
printf("%d\n", res);
}
return 0;
}
测试案例
-
输入矩阵:
1 2 3
4 5 6
7 8 9
-
预处理 s 矩阵(部分):s [2][2] = 1+2+4+5=12,s [3][3] = 45
-
查询子矩阵 (1,1,2,2):12,查询 (2,2,3,3):5+6+8+9=28
-
输出:12、28