開啟章節選單
CSES Static Range Sum Queries
解題思路
如果用最暴力的方式求區間和的話,每一次詢問的時間複雜度為 ,而因為有 次詢問,時間複雜度高達 ,太慢了
這時候我們就可以使用前綴和!
根據「前綴和」的章節所述,我們可以利用前綴和來每次詢問以 的速度,加上 的預處理求出區間和。
首先,我們先預處理前綴和:
for (int i = 1; i <= n; i++) { psum[i] = psum[i - 1] + a[i]; }
接著,我們便可以用以下公式求出第 個元素到第 個元素的區間和。
sum = psum[r] - psum[l - 1];
常見錯誤
long long
其中一個可能會犯的錯誤就是使用 int
資料型態。
雖然陣列中的每一個值都在 int
的範圍內,但是區間和有機會超過 int
的範圍(約等於 )
所以,我們的 陣列應該使用 long long
資料型態才能避免溢位!
減一 / 加一
在求區間和的時候,記得要將 減 ,不然區間和不會包含到 這個數字。 因為 和 都是從 開始,所以不需要多做加一的動作。
完整程式碼
#include <iostream> #include <vector> using namespace std; int main() { int n, q; cin >> n >> q; vector<long long> x(n + 1), psum(n + 1); // 注意,因為此程式嗎為 1-based,陣列大小要開成 n + 1 for (int i = 1; i <= n; i++) { cin >> x[i]; psum[i] = psum[i - 1] + x[i]; } for (int i = 1; i <= q; i++){ int a, b; cin >> a >> b; cout << psum[b] - psum[a - 1] << "\n"; } }
小技巧
C++ 裡面也有 prefix sum 的函式,其重要引入標頭檔 <numeric>
。(雖然這樣沒有比較好寫)
這樣原本計算前綴和的部分可以用此程式嗎取代:
vector<long long> x(n + 1); int psum[200005]; for (int i = 1; i <= n; i++) { cin >> x[i]; } partial_sum(x.begin(), x.end(), psum);