写在前面:
1. 前缀和的标志就是求一个区间的和
2. 用a命名原数组,s命名前缀和数组
3. 原数组和前缀和数组的第一项往往是从下标1开始的,目的是防止s[i] = s[i - 1] + a[i]这段代码越界。
4. 前缀和问题一般考察一维形式和二维形式。
一维形式的核心代码是:
s[i] = s[i - 1] + a[i]
二维形式的核心代码是:
s[i][j] = s[i -1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]
5. 从左上角点(x1, y1)到右下角(x2, y2)这个矩形范围的和为:
s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]
6.当写熟练后可以将原数组a合并到前缀和数组s中。
AcWing 795. 前缀和
AcWing 795. 前缀和
这是一道最经典,最简单的前缀和问题。
#include<iostream>
using namespace std;
const int N = 100010;
int a[N], s[N];
int main() {
int n, m;
cin >> 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;
}
AcWing 796. 子矩阵的和
最终代码:
#include<iostream>
using namespace std;
const int N = 1010;
int 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", &s[i][j]);
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + s[i][j];
}
int x1, y1, x2, y2;
while (q--) {
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;
}