Khoá học C++ nâng cao
Bài học: Kỹ Thuật Mảng: Hai Con Trỏ, Cửa Sổ Trượt, Mảng Tiền Tố & Mảng Hiệu
🏆 +100 XP tiềm năng Thoát

Kỹ Thuật Mảng: Hai Con Trỏ, Cửa Sổ Trượt, Mảng Tiền Tố & Mảng Hiệu

2 khối nội dung 45 phút học tập MỞ BẢNG TRẮNG

Kỹ Thuật Mảng: Hai Con Trỏ, Cửa Sổ Trượt, Mảng Tiền Tố & Mảng Hiệu

Nội dung bài học

1. Khái niệm & bản chất của tối ưu hóa tuyến tính trên mảng

Trong lập trình thi đấu, các kỹ thuật xử lý mảng như Hai con trỏ (Two Pointers), Cửa sổ trượt (Sliding Window), Mảng tiền tố (Prefix Sum), Mảng hiệu (Difference Array)Nén tọa độ (Coordinate Compression) là bộ công cụ nền tảng giúp chuyển đổi các thuật toán ngây thơ đa biến $\mathcal{O}(N^2)$ hoặc $\mathcal{O}(N \times Q)$ về độ phức tạp tối ưu tuyến tính $\mathcal{O}(N)$ hoặc $\mathcal{O}(N \log N)$.

Ở Level 2, ta tập trung vào Kỹ thuật kết hợp đa chiều & Mảng 2D:

  • Hai con trỏ co giãn & Cửa sổ trượt linh hoạt: Duy trì bất biến về tần suất, số lượng phần tử phân biệt hoặc tổng điều kiện khi kích thước cửa sổ thay đổi liên tục.
  • Mảng tiền tố 2D (2D Prefix Sum): Trả lời truy vấn tính tổng hình chữ nhật con bất kỳ trên ma trận $N \times M$ trong $\mathcal{O}(1)$.
  • Mảng hiệu 2D (2D Difference Array): Cập nhật cộng một giá trị lên toàn bộ vùng hình chữ nhật trong $\mathcal{O}(1)$ và khôi phục ma trận trong $\mathcal{O}(NM)$.
  • Nén tọa độ (Coordinate Compression): Ánh xạ các giá trị rời rạc rất lớn ($A_i \le 10^9$) về dải chỉ số nhỏ liên tiếp $[1, N]$ mà vẫn bảo toàn hoàn toàn quan hệ thứ tự $A_i < A_j$.

Sơ đồ 2D Prefix Sum

2. Mảng tiền tố 2D

2.1. Công thức Mảng tiền tố 2D (2D Prefix Sum)

Định nghĩa: $pref[i][j]$ là tổng các phần tử trong hình chữ nhật từ góc trên-trái $(1, 1)$ đến $(i, j)$: $$pref[i][j] = pref[i-1][j] + pref[i][j-1] - pref[i-1][j-1] + A[i][j]$$

Truy vấn tổng hình chữ nhật từ $(x_1, y_1)$ đến $(x_2, y_2)$ trong $\mathcal{O}(1)$: $$\text{Sum}(x_1, y_1, x_2, y_2) = pref[x_2][y_2] - pref[x_1-1][y_2] - pref[x_2][y_1-1] + pref[x_1-1][y_1-1]$$

2.2. Công thức Mảng hiệu 2D (2D Difference Array)

Để cộng thêm giá trị $V$ vào toàn bộ hình chữ nhật $[x_1, y_1] \to [x_2, y_2]$ trong $\mathcal{O}(1)$:

  1. $diff[x_1][y_1] \mathrel{+}= V$
  2. $diff[x_1][y_2 + 1] \mathrel{-}= V$
  3. $diff[x_2 + 1][y_1] \mathrel{-}= V$
  4. $diff[x_2 + 1][y_2 + 1] \mathrel{+}= V$

Sau khi thực hiện tất cả các cập nhật, chạy công thức Prefix Sum 2D trên mảng $diff$ để thu lại giá trị thực tế của ma trận.


3. Kỹ thuật nén tọa độ (Coordinate Compression)

3.1. Động lực & Cơ chế thực thi

Khi một bài toán có các giá trị tọa độ $X_i \in [-10^9, 10^9]$ nhưng số lượng điểm $N \le 10^5$, ta không thể dùng mảng đánh dấu kích thước $10^9$.
Ta nén các giá trị này về tập $\{0, 1, \dots, K-1\}$ với $K \le N$:

vector<int> vals = a;
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());

// Tìm chỉ số đã nén (0-based) của a[i] trong O(log N)
for (int i = 0; i < n; ++i) {
    int compressed_val = lower_bound(vals.begin(), vals.end(), a[i]) - vals.begin();
}

4. Kỹ thuật hai con trỏ co giãn (Dynamic Sliding Window)

4.1. Bài toán: Tìm đoạn con ngắn nhất có tổng $\ge S$

Với mảng gồm các số nguyên dương $A_i > 0$:

  • Khi mở rộng con trỏ phải $R$, tổng current_sum tăng ngặt.
  • Khi current_sum >= S, ta thu hẹp con trỏ trái $L$ để tìm độ dài ngắn nhất thỏa mãn.
int min_len = n + 1;
long long current_sum = 0;
int l = 0;

for (int r = 0; r < n; ++r) {
    current_sum += a[r];
    while (current_sum >= s) {
        min_len = min(min_len, r - l + 1);
        current_sum -= a[l];
        l++;
    }
}

5. Mẫu cài đặt chuẩn thi đấu: 2D Prefix Sum

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m, q;
    if (!(cin >> n >> m >> q)) return 0;

    vector<vector<long long>> a(n + 1, vector<long long>(m + 1, 0));
    vector<vector<long long>> pref(n + 1, vector<long long>(m + 1, 0));

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            cin >> a[i][j];
            pref[i][j] = pref[i - 1][j] + pref[i][j - 1] - pref[i - 1][j - 1] + a[i][j];
        }
    }

    while (q--) {
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        long long ans = pref[x2][y2] - pref[x1 - 1][y2] - pref[x2][y1 - 1] + pref[x1 - 1][y1 - 1];
        cout << ans << "\n";
    }
    return 0;
}

6. Ranh giới áp dụng

Kỹ Thuật Phạm Vi Sử Dụng Độ Phức Tạp
Two Pointers / Sliding Window Mảng 1D đơn điệu, tìm đoạn con thỏa mãn tính chất $\mathcal{O}(N)$
2D Prefix Sum Truy vấn tổng ma trận con tĩnh Tiền xử lý $\mathcal{O}(NM)$, truy vấn $\mathcal{O}(1)$
2D Difference Array Cập nhật cộng hình chữ nhật hàng loạt rồi mới truy vấn Cập nhật $\mathcal{O}(1)$, khôi phục $\mathcal{O}(NM)$
Coordinate Compression Tọa độ lớn $10^9$ cần đưa về dải nhỏ để làm mảng đếm/cây $\mathcal{O}(N \log N)$

1
A
B
C
D
2
A
B
C
D
3
A
B
C
D

Bài tập lập trình vận dụng

22 Bài tập thực hành

Nhấn vào nút "Làm bài" bên dưới để mở giao diện làm bài trực tuyến (Online Judge) và thực hiện viết mã nguồn cho bài tập này.

Truy vấn tổng ma trận con 2d
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Cập nhật hình chữ nhật ma trận 2d
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đoạn con ngắn nhất có tổng $\ge s$
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Nén tọa độ & đếm tần suất trên dải lớn
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đoạn con dài nhất có không quá k số khác nhau
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Ma trận con có tổng lớn nhất (maximum submatrix sum)
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Diện tích phủ bởi các hình chữ nhật rời rạc
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đếm cặp đoạn thẳng chồng lấn nhau
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Cửa sổ trượt đếm số lượng xâu anagram
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đếm hình vuông con có tổng đúng bằng k
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Khử chiều 3-sum & 4-sum hai con trỏ
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đếm số đoạn con có hiệu max - min $\le k$
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đoạn con ngắn nhất chứa đầy đủ bảng chữ cái
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Mảng hiệu trên cây (Tree difference array)
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đếm tam giác có độ dài cạnh hợp lệ
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Quét đường thẳng nén tọa độ (sweep-line area 2d)
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Diện tích hợp các hình chữ nhật
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Mảng hiệu trên hình vuông xoay 45 độ
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Nen toa do da chieu 3d
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đếm số bộ ba tam giác hợp lệ
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Đếm xâu con có đúng k ký tự khác nhau
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài
Ma tran tong lon nhat Kadane 2d
Độ khó: mediumĐiểm tối đa: 100.0 điểm
Làm bài