快轉到主要內容

CSES Static Range Sum Queries

目錄

解題思路
#

如果用最暴力的方式求區間和的話,每一次詢問的時間複雜度為 \(O(n)\),而因為有 \(q\) 次詢問,時間複雜度高達 \(O(nq)\),太慢了

這時候我們就可以使用前綴和!

根據「前綴和」的章節所述,我們可以利用前綴和來每次詢問以 \(O(1)\) 的速度,加上 \(O(n)\) 的預處理求出區間和。

首先,我們先預處理前綴和:

for (int i = 1; i <= n; i++) {
    psum[i] = psum[i - 1] + a[i];
}

接著,我們便可以用以下公式求出第 \(l\) 個元素到第 \(r\) 個元素的區間和。

sum = psum[r] - psum[l - 1];

常見錯誤
#

long long
#

其中一個可能會犯的錯誤就是使用 int 資料型態。
雖然陣列中的每一個值都在 int 的範圍內,但是區間和有機會超過 int 的範圍(約等於 \(2 \times 10^9\))
所以,我們的 \(psum\) 陣列應該使用 long long 資料型態才能避免溢位!

減一 / 加一
#

在求區間和的時候,記得要將 \(l\) 減 \(1\),不然區間和不會包含到 \(l\) 這個數字。
因為 \(l\) 和 \(r\) 都是從 \(1\) 開始,所以不需要多做加一的動作。

完整程式碼
#

#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);
Piau 的筆記本
作者
Piau 的筆記本
希望我寫下來的東西能夠長久的記在我的腦中