前缀和
前缀和是一种重要的预处理,能大大降低查询的时间复杂度。我们可以简单理解为“数列的前 n n n 项的和”。
例题
有 N N N 个的正整数放到数组 A A A 里,现在要求一个新的数组 B B B,新数组的第 i i i 个数 B [ i ] B[i] B[i]是原数组 A A A 第 0 0 0 到第 i i i 个数的和。
对于这道题,我们有两种做法:
- 把对数组 A A A 的累加依次放入数组 B B B 中。
- 递推: B [ i ] = B [ i − 1 ] + A [ i ] B[i] = B[i-1] + A[i] B[i]=B[i−1]+A[i] ,前提是 B [ 0 ] = A [ 0 ] B[0] = A[0] B[0]=A[0] 。
#include<bits/stdc++.h>
#define re register
#define f(i, a, b) for(re int i = a; i < b; i++)
using namespace std;
int N;
signed main(){
scanf("%d", &N);
int A[N + 1], B[N + 1];
f(i, 0, N) scanf("%d", &A[i]);
B[0] = A[0];
f(i, 1, N) B[i] = B[i - 1] + A[i];
f(i, 0, N) printf("%d ", B[i]);
printf("\n");
return 0;
}
二维/多维前缀和
其实前缀和几乎都是基于容斥原理
e g . eg. eg.有这样一个矩阵:
1
\boxed{1}
1
2
\boxed{2}
2
4
\boxed{4}
4
3
\boxed{3}
3
5
\boxed{5}
5
1
\boxed{1}
1
2
\boxed{2}
2
4
\boxed{4}
4
6
\boxed{6}
6
3
\boxed{3}
3
5
\boxed{5}
5
9
\boxed{9}
9
我们先定义个矩阵 s u m x , y = ∑ i = 1 x ∑ j = 1 y a i , j sum_{x,y}=\sum\limits_{i=1}^x\sum\limits_{j=1}^ya_{i, j} sumx,y=i=1∑xj=1∑yai,j
那么这个矩阵的前缀和就是:
就拿 “ 15 ” “15” “15”来举例:
s u m 2 , 3 = s u m 1 , 3 + s u m 2 , 2 − s u m 1 , 2 + a 2 , 3 sum_{2,3}=sum_{1,3}+sum_{2,2}-sum_{1,2}+a_{2,3} sum2,3=sum1,3+sum2,2−sum1,2+a2,3
即 s u m 2 , 3 = 9 + 7 − 3 + 2 = 15 sum_{2,3}=9+7-3+2=15 sum2,3=9+7−3+2=15
⟹ s u m i , j = s u m i − 1 , j + s u m i , j − 1 − s u m i − 1 , j − 1 + a i , j \implies sum_{i,j}=sum_{i-1,j}+sum_{i,j-1}-sum_{i-1,j-1}+a_{i,j} ⟹sumi,j=sumi−1,j+sumi,j−1−sumi−1,j−1+ai,j
应用
求 ( x 1 , y 1 ) − ( x 2 , y 2 ) (x_1,y_1)-(x_2,y_2) (x1,y1)−(x2,y2)子矩阵的和,类比以上的做法,易得: s u m x 2 , y 2 − s u m x 1 − 1 , y 2 − s u m x 2 , y 1 − 1 + s u m x 1 − 1 , y 1 − 1 \boxed{sum_{x_2,y_2}-sum_{x_1-1,y_2}-sum_{x_2,y_1-1}+sum_{x_1-1,y_1-1}} sumx2,y2−sumx1−1,y2−sumx2,y1−1+sumx1−1,y1−1