前缀和

作用:快速求区间和

公式:$s[i]=s[i-1]+a[i]$,其中$s[i]$表示前$i$项的和

例:给定一个$n$项的数列$a$,共$m$次询问,每次询问给出两个数$l,r$,求区间$[l,r]$的和

分析:区间$[l,r]$的和即为前$r$项的和减去前$l-1$项的和,即$s[r]-s[l-1]$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5;
int n,m;
int s[N];

int main(){
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> s[i];
s[i]+=s[i-1];
}
for(int i=1;i<=m;i++){
int l,r;
cin >> l >> r;
cout << s[r]-s[l-1] << endl;
}
return 0;
}

二维前缀和

用$s[i][j]$表示前$i$行每行的前$j$个数之和

$s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]$

例:给定一个$n*n$的矩阵,求最大子矩阵和

分析:左上角为$(x_1,y_1)$,右下角为$(x_2,y_2)$的矩阵和为$s[x_2][y_2]-s[x_1-1][y_2]-s[x_2][y_1-1]+s[x_1-1][y_1-1]$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<bits/stdc++.h>
using namespace std;

const int N=105;
int n;
int s[N][N];
int ans=-1e9;

int sum(int a,int b,int c,int d){
return s[c][d]-s[a-1][d]-s[c][b-1]+s[a-1][b-1];
}

int main(){
cin >> n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin >> s[i][j];
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
for(int x_1=1;x_1<=n;x_1++){
for(int y_1=1;y_1<=n;y_1++){
for(int x_2=x_1;x_2<=n;x_2++){
for(int y_2=y_1;y_2<=n;y_2++){
ans=max(ans,sum(x_1,y_1,x_2,y_2));
}
}
}
}
cout << ans;
return 0;
}