前言
如题,前缀和在近年的CSP考试中时常作为第二题剩下的20-30分的解法出现,以下是出现的考题:
202309-2 坐标变换(其二)
202104-2 邻域均值
202203-2 出行计划
还有一些比如 2021-09-2 非零段划分(差分,前缀和的变种) 这样不一定需要前缀和也可以得到剩下的30分的解法 ,没有列举出来。
前缀和基础
具体的讲解网上比比皆是,不展开说了
一维数组前缀和
求的是一维数组 [L,R](L<=R)
区间内的元素之和:
sum[L,R] = sum[R] - sum[L-1]
sum[L] = num[1] +...+num[L-1]+num[L]
以下两式上下做差即可得答案
sum[R] = num[1] +...+num[L-1]+num[L] +...+num[R]
sum[L-1] = num[1] +...+num[L-1]
#include <iostream>
using namespace std;
int num[100];
int sum[100];
int ans[100];
int main(){
int n,m;
cin >> n>> m;
sum[0] = 0;
for(int i = 1;i <= n;i++){
cin >> num[i];
sum[i] = sum[i-1] + num[i];
}
for(int i = 1;i <= m;i++){
int L,R;
cin >> L >> R;
ans[i] = sum[R] - sum[L-1];
}
for(int i = 1;i <= m;i++){
cout << ans[i] << endl;
}
return 0;
}
二维数组前缀和
求的是 (x1,y1)
到 (x2,y2)
范围内元素的和
Q:如何理解如 sum[x2][y1-1]
中-1
的意思?
A:类比一维数组前缀和 sum[L,R] = sum[R] - sum[L-1]
,sum[R]
中包含了sum[L](R>=L)
的部分,所以减掉sum[L-1]
。同理,要留下从 (x1,y1)
到 (x2,y2)
范围内元素的和,需要把x1
和y1
之前的部分减去。
#include <iostream>
using namespace std;
//int num[100][100];
int sum[100][100];
int main(){
int n,m,q;
cin >> n >> m >> q;
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++){
cin >> sum[i][j];
}
}
/*
* 初始化二维数组的前缀和:更新后表示从(1,1)到(i,j)的累计值
* 只在原数组中更新即可,不需要建立新的数组,
* 这里的sum[i][j]就是当前那一格的值,更新后,才成为二维前缀和。
*/
for(int i = 1;i <= n;i++){
for(int j = 1; j <= m;j++){
sum[i][j] += sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1];
}
}
/*
* 计算从(x1,y1)到(x2,y2)的元素之和
*/
for(int i = 0;i < q;i++){
int x1,y1,x2,y2;
cin >> x1 >> y1 >> x2 >> y2;
//+ sum[x1-1][y1-1]:这个区域被减了两次,需要补上一次
cout << sum[x2][y2] - sum[x2][y1-1] - sum[x1-1][y2] + sum[x1-1][y1-1];
}
return 0;
}