(一)前綴和算法
概念:前綴和就是數組的前i項之和
一維前綴和
s[1]=a[1]
s[2]=a[1]+a[2]
s[3]=a[1]+a[2]+a[3]
s[4]=a[1]+a[2]+a[3]+a[4]
s[5]=a[1]+a[2]+a[3]+a[4]+a[5]
①.前綴和
輸入一個長度為n的整數序列。
接下來再輸入m個詢問,每個詢問輸入一對l, r。
對於每個詢問,輸出原序列中從第l個數到第r個數的和。
輸入格式
第一行包含兩個整數n和m。
第二行包含n個整數,表示整數數列。
接下來m行,每行包含兩個整數l和r,表示一個詢問的區間范圍。
輸出格式
共m行,每行輸出一個詢問的結果。
數據范圍
1≤l≤r≤n,
1≤n,m≤100000,
−1000≤數列中元素的值≤1000
輸入樣例:
5 3 2 1 3 6 4 1 2 1 3 2 4
輸出樣例:
3 6 10
#include<iostream> using namespace std; int main() { int sum,n,i,j,x,m,l,r; int s[100009]; cin>>n>>m; sum=0; for(i=1;i<=n;i++) { cin>>x; sum+=x; s[i]=sum; } for(i=0;i<m;i++) { cin>>l>>r; cout<<s[r]-s[l-1]<<endl; } return 0; }
在做題中我們會經常用到他的二維的前綴和數組
最常見的案例:求子矩陣的和
2.子矩陣的和
輸入一個n行m列的整數矩陣,再輸入q個詢問,每個詢問包含四個整數x1, y1, x2, y2,表示一個子矩陣的左上角坐標和右下角坐標。
對於每個詢問輸出子矩陣中所有數的和。
輸入格式
第一行包含三個整數n,m,q。
接下來n行,每行包含m個整數,表示整數矩陣。
接下來q行,每行包含四個整數x1, y1, x2, y2,表示一組詢問。
輸出格式
共q行,每行輸出一個詢問的結果。
數據范圍
1≤n,m≤1000,
1≤q≤200000,
1≤x1≤x2≤n,
1≤y1≤y2≤m,
−1000≤矩陣內元素的值≤1000
輸入樣例:
3 4 3 1 7 2 4 3 6 2 8 2 1 2 3 1 1 2 2 2 1 3 4 1 3 3 4
輸出樣例:
17 27 21
對於二維前綴和問題,首先我們先求出他的前綴和數組,如何求呢?
對於(i,j)該點的前綴和數組求解:看圖,求紅色部分的前綴和

就可以看成是藍色前綴和+粉色前綴和-黃色前綴和+自己本身
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]
求完前綴和數組后,在分析一下如果要求兩個點之間的子矩陣的和應該怎么辦?
再畫圖分析一下:
求解兩個圓圈之間的子矩陣:黃色面積-藍色面積-紫色面積+粉色面積
ans=s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1]
代碼:
#include<iostream> #include<cstdio> using namespace std; int n,m,q,x1,x2,y1,y2; int s[1010][1010],a[1010][1010]; int main() { int i,j; scanf("%d%d%d",&n,&m,&q); for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { scanf("%d",&a[i][j]); s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]; } } while(q--) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); printf("%d\n",s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1]); } return 0; }