前綴和(Prefix(Prefix(Prefix Sum)Sum)Sum)的定義
前綴和是一種高效處理區間求和問題的算法技巧
其核心思想是通過預處理構建一個前綴和數組
使得后續的區間和查詢可以在常數時間O(1)O(1)O(1)內完成
核心概念
- 定義
給定一個數組a[1...n]a[1...n]a[1...n],其前綴和數組s[1...n]s[1...n]s[1...n]定義為:
s[0]=0(邊界條件)s[0]=0(邊界條件)s[0]=0(邊界條件)
s[i]=a[1]+a[2]+...+a[i](前i個元素的和)s[i]=a[1]+a[2]+...+a[i](前i個元素的和)s[i]=a[1]+a[2]+...+a[i](前i個元素的和)
通過遞推計算:s[i]=s[i?1]+a[i]s[i]=s[i-1]+a[i]s[i]=s[i?1]+a[i] - 作用
快速計算區間和:查詢a[l...r]a[l...r]a[l...r]的和時,只需計算s[r]?s[l?1]s[r]-s[l-1]s[r]?s[l?1],無需遍歷整個區間。
優化時間復雜度:
預處理:O(n)O(n)O(n)
單次查詢:O(1)O(1)O(1)
適用于頻繁查詢但數據不頻繁修改的場景(如靜態數組)
對比其他方法差距/使用前綴和的原因
方法 | 預處理時間 | 單次查詢時間 | 適用場景 |
---|---|---|---|
暴力遍歷 | O(1) | O(n) | 查詢極少 |
前綴和 | O(n) | O(1) | 查詢多,數據靜態 |
線段樹/樹狀數組 | O(n) | O(log n) | 查詢和修改都頻繁 |
總結
前綴和通過空間換時間,將區間和查詢優化至O(1)O(1)O(1),是算法競賽中的常客
若需支持動態修改,可結合差分數組或升級為樹狀數組/線段樹
前綴和代碼模板示例
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],s[N];
int main(){int n,q;//n=數組個數,q=詢問次數cin>>n>>q;for(int i=1;i<=n;i++){cin>>a[i];//讀入初值s[i]=s[i-1]+a[i];//計算前綴和}for(int i=1;i<=q;i++){int l,r;//詢問區間cin>>l>>r;cout<<s[r]-s[l-1]<<endl;//輸出區間和}return 0;
}
原理
非常EasyEasyEasy
前綴和數組s[x]s[x]s[x]的值相當于a[1]a[1]a[1]~a[x]a[x]a[x]
利用這個原理計算得知
a[l]到a[r]的和=s[r]?s[l?1]a[l]到a[r]的和=s[r]-s[l-1]a[l]到a[r]的和=s[r]?s[l?1]
例題
P8218 【深進1.例1】求區間和
題目描述
給定由 nnn 個正整數組成的序列 a1,a2,?,ana_1, a_2, \cdots, a_na1?,a2?,?,an? 和 mmm 個區間 [li,ri][l_i,r_i][li?,ri?],分別求這 mmm 個區間的區間和。
輸入格式
第一行包含一個正整數 nnn,表示序列的長度。
第二行包含 nnn 個正整數 a1,a2,?,ana_1,a_2, \cdots ,a_na1?,a2?,?,an?。
第三行包含一個正整數 mmm,表示區間的數量。
接下來 mmm 行,每行包含兩個正整數 li,ril_i,r_ili?,ri?,滿足 1≤li≤ri≤n1\le l_i\le r_i\le n1≤li?≤ri?≤n。
輸出格式
共 mmm 行,其中第 iii 行包含一個正整數,表示第 iii 組答案的詢問。
輸入輸出樣例 #1
輸入 #1
4
4 3 2 1
2
1 4
2 3
輸出 #1
10
5
說明/提示
樣例解釋
第 111 到第 444 個數加起來和為 101010。第 222 個數到第 333 個數加起來和為 555。
數據范圍
對于 50%50 \%50% 的數據:n,m≤1000n,m\le 1000n,m≤1000;
對于 100%100 \%100% 的數據:1≤n,m≤1051 \le n, m\le 10^51≤n,m≤105,1≤ai≤1041 \le a_i\le 10^41≤ai?≤104。
分析
經典的前綴和例題
看輸入要求,輸入數組個數nnn
然后給數組a[]a[]a[]初值,再輸入詢問次數mmm
給mmm行的li,ril_i,r_ili?,ri?并詢問a[li]到a[ri]a[l_i]到a[r_i]a[li?]到a[ri?]的區間和
跟模板一樣,但是需要把mmm的輸入改到輸入數組a[]a[]a[]的后方
ACACAC代碼
#include<iostream>
using namespace std;
const int N=1e6+10;
int a[N],s[N];
int main(){int n,m;//n=數組個數,m=詢問次數cin>>n;for(int i=1;i<=n;i++){cin>>a[i];//讀入初值s[i]=s[i-1]+a[i];//計算前綴和}cin>>m;for(int i=1;i<=m;i++){int l,r;//詢問區間cin>>l>>r;cout<<s[r]-s[l-1]<<endl;//輸出區間和}return 0;
}
題單附送
題單題單題單
包含前綴和、差分、離散化