快轉到主要內容

CSES-1660 Subarray Sums I

標籤: 雙指標
目錄


題目連結:https://cses.fi/problemset/task/1660

題意
#

題目給定由 \( n \) 個正整數組成的陣列,與目標總和 \( x \)。
我們需要求出有幾個「連續的子陣列(Subarray)」其數字總和等於目標值 \( x \)。

思路
#

陣列全為正整數具有重要的單調性質:當連續區間加長時,數字總和必然增加。
有了單調遞增的特性,便可使用「雙指標(滑動視窗 Sliding Window)」來達成 \(\mathcal{O}(N)\) 的解法。

設定左指標 l 與右指標 r 起始於陣列最左端:

  1. 右指標拓展:將 r 指標向右推進,將新數字加入區間總和(sum)。
  2. 左指標收縮:若區間總和「大於」目標值 \( x \),則將左指標 l 向右縮減,從 sum 減去左側數字,直到總和回到不大於 \( x \) 的範圍。
  3. 結算:調整後,若區間總和剛好等於目標值(sum == x),則找到一組連續子陣列,將答案計數加一。

雙指標由左至右掃描一次,即可找出所有符合條件的區間。

程式碼
#

#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define fi first
#define se second
#define INF LONG_LONG_MAX/1000
#define WA() cin.tie(0)->sync_with_stdio(0)
#define all(x) (x).begin(), (x).end()
#define int long long
#define PII pair<int, int>

signed main() { WA();
    int n, x; cin >> n >> x;
    vector<int> v(n);
    for (auto &i : v) cin >> i;
    
    int ans = 0;
    
    // l 為左邊界,r 為右邊界,sum 為目前滑動視窗內的總和
    for (int l = 0, r = 0, sum = 0; r < n;) {
        // 右指標向右伸展,加入新數字到 sum
        sum += v[r++];
        
        // 總和超過目標值 x 時,左指標向右收縮,減去左側數字
        while (sum > x) sum -= v[l++]; 
        
        // 若區間總和精準等於目標 x,則記錄一組答案
        if (sum == x) ans++;
    }
    
    cout << ans;
}
Piau 的筆記本
作者
Piau 的筆記本
希望我寫下來的東西能夠長久的記在我的腦中