Wiki Kỹ năng giải bài Tiếp cận bài toán mới

Tiếp cận bài toán mới

huunguyen huunguyen Updated Tháng tư 3, 2026

Khi gặp một bài toán mới, đừng vội code ngay. Hãy theo quy trình dưới đây để tránh mất thời gian vào hướng sai.

Quy trình 5 bước

Bước 1: Đọc kỹ đề
  • Đọc toàn bộ đề ít nhất hai lần.
  • Gạch chân các từ khóa quan trọng: "lớn nhất", "nhỏ nhất", "đúng một lần", "liên tiếp"...
  • Xác định rõ: Input là gì? Output là gì?
  • Đọc kỹ ràng buộc (N, giá trị các phần tử, số test case).
Bước 2: Thử ví dụ mẫu bằng tay

Trước khi nghĩ thuật toán, hãy tự giải bằng tay các ví dụ trong đề. Điều này giúp bạn:

  • Hiểu đúng yêu cầu bài.
  • Phát hiện các trường hợp đặc biệt sớm.
  • Có trực giác về hướng giải.
Bước 3: Xác định độ phức tạp cần thiết

Từ ràng buộc N, xác định thuật toán cần có độ phức tạp gì:

N Độ phức tạp
103 O(N2) được
105 Cần O(NlogN) hoặc O(N)
109 Cần O(logN) hoặc O(N)
Bước 4: Nghĩ thuật toán

Xem xét từng hướng từ đơn giản đến phức tạp:

  1. Brute force có được không? (thường O(N2) hoặc O(N!))
  2. Có thể sắp xếp để đơn giản hóa không?
  3. Có thể dùng tìm kiếm nhị phân trên đáp án không?
  4. cấu trúc con tối ưu → thử DP?
  5. lựa chọn tham lam rõ ràng → thử Greedy?
  6. Bài toán liên quan đến đồ thị → BFS/DFS/Dijkstra...?
Bước 5: Cài đặt và kiểm tra
  • Code từng phần nhỏ, kiểm tra từng bước.
  • Test với ví dụ trong đề trước.
  • Tự tạo thêm test case: trường hợp nhỏ nhất (N=1), lớn nhất (N=105), trường hợp đặc biệt.

Kỹ thuật: Simplify the Problem

Nếu bài quá khó, hãy đơn giản hóa trước:

  • Giả sử N nhỏ (chỉ 5-10 phần tử) — giải brute force.
  • Bỏ bớt ràng buộc — giải phiên bản dễ hơn.
  • Giải bài 1D trước khi nghĩ đến 2D.

Sau khi hiểu bài đơn giản hơn, dần dần mở rộng lên bài gốc.


Kỹ thuật: Think Backwards

Với một số bài, suy nghĩ ngược lại (từ đáp án về đầu vào) dễ hơn:

  • Bài xóa phần tử → thêm phần tử theo thứ tự ngược.
  • Bài đồ thị tách → đồ thị gộp (DSU).

Các tín hiệu nhận biết thuật toán

Từ khóa trong đề Hướng giải
"Đường đi ngắn nhất" BFS (không trọng số), Dijkstra (trọng số dương)
"Tổng lớn nhất / nhỏ nhất trên đoạn" Prefix sum, Segment Tree
"Số lần xuất hiện" Hash map
"Dãy con tăng dài nhất" DP — LIS
"Kết nối / cùng nhóm" DSU
"Tất cả tập con" Bitmask DP
"In ra có / không" Thường là DP hoặc Greedy
"K nhỏ nhất / lớn nhất" Heap / Binary search
gnatmake 12.2.0 a68g 3.1.2 nasm 2.16.1 as_x64 2.46 awk 1.3.4 gcc 16.1.0 csc 6.12.0.200 g++ 16.1.0 g++-themis 16.1.0 g++17 16.1.0 g++20 16.1.0 g++23 16.1.0 clang++ 22.1.6 dmd 2.112.0 dart 3.12.1 gforth 0.7.3 gfortran 12.2.0 go 1.26.3 groovyc 5.0.6 javac 25.0.3 node 26.2.0 kotlinc 2.3.21 sbcl 2.2.9 lua 5.4.8 nim 2.2.10 fpc 3.2.2 fpc-themis 3.2.2 perl 5.36.0 php 8.5.6 pike 8.0 pypy3 7.3.23 python3 3.14.5 racket 8.7 ruby 4.0.5 rustc 1.96.0 csc 5.3.0 ctoj-scratch 0.0.1 sed 4.9 tclsh 8.6 bun 1.3.14 deno 2.8.1 v 0.5.1 zig 0.16.0