You are on page 1of 5

Lớp Competitive Programming

1 năm - 12 tháng
Mỗi tháng có 8 buổi
7 buổi học về lý thuyết + bài tập
buổi số 8 là buổi làm một bài test để review kiến thức đã học trong tháng đó

Mỗi buổi học từ 19h30 -> 22h00, tối thứ 2 và thứ 6 hàng tuần.
Mỗi buổi học luôn có video quay lại.

Giai đoạn 1: (6 tháng đầu tiên - những kiến thức căn bản trong sách giáo khoa
chuyên tin mà một bạn học chương trình thuật toán phải biết)

- Tháng 1: Giới thiệu thuật toán + Thư viện STL


+ Giới thiệu về thuật toán (Độ phức tạp thuật toán, hàm sắp xếp, vector)
+ Stack (làm bài về stack)
+ Queue (làm bài về queue)
+ Heap
+ Làm bài tập về Heap
+ Binary Search Tree (set)
+ Binary Search Tree (map)
+ Bitset
+ Làm một bài tập cuối tháng

- Tháng 2: Problem Solving Paradigsm


+ Kỹ thuật two pointers
+ Thuật toán Binary Search
+ Thuật toán Binary Search (Binary search the answer)
+ Thuật toán Binary Search (Binary search on float và Ternary Search)
+ Kỹ thuật Greedy
+ Kỹ thuật Recursion + Divide and Conquer
+ Làm bài tập Divide and conquer
+ Làm bài tập cuối tháng

- Tháng 3: Dynamic Programming


+ Giới thiệu về quy hoạch động
+ Làm bài tập quy hoạch động cổ điển
+ Làm bài tập quy hoạch động nâng cao
+ Làm bài tập quy hoạch động nâng cao (level 2)
+ Làm bài tập quy hoạch động nâng cao (level 3)
+ Đổi biến số trong quy hoạch động
+ Làm bài tập về đổi biến số
+ Kỳ thi cuối tháng

- Tháng 4: Graph Theory


+ Giới thiệu cơ bản về đồ thị, thuật toán DFS
+ Sắp xếp Topo
+ Tìm khớp / cầu trên đồ thị
+ Tìm thành phần liên thông mạnh trên đồ thị
+ Thuật toám BFS
+ Thuật toán Dijkstra tối ưu
+ Disjoint set union Finds và thuật toán Kruskal
+ Kỳ thi cuối tháng

- Tháng 5: Toán
+ Combinatorics
+ Dynamic Programming + Combinatorics
+ Xác suất
+ Kỳ vọng
+ Lý thuyết trò chơi
+ Phi hàm Euler
+ Một số phương pháp chứng minh trong toán học
+ Kỳ thi cuối tháng

- Tháng 6: Ôn lại kiến thức

Giai đoạn 2 (6 tháng sau - Dành cho những bạn muốn thi bảng siêu cúp, hoặc muốn có
giải 3 đổ lên của kỳ thi acm icpc, hoặc giải 3 học sinh giỏi quốc gia đổ lên)

- Tháng 7: Data Structure nâng cao


+ Segment Tree (Cây phân đoạn)
+ Fenwick Tree (Cây chỉ số nhị phân)
+ Làm bài tập về 2 loại cây này
+ Trie (Cây tiền tố)
+ Làm bài tập về cây Trie
+ Suffix Array
+ Treap
+ Làm kỳ thi về Data Structure

- Tháng 8: Học những thuật toán tìm kiếm nâng cao


+ Kỹ thuật chia căn (MO algorithm)
+ Kỹ thuật chia đoạn
+ Kỹ thuật Meet in the middle
+ RMQ
+ Làm bài tập về RMQ
+ Hash (thuật toán để mã hóa chuỗi)
+ KMP
+ Làm kỳ thi

- Tháng 9: Dynamic Programming Advanced


+ Digit Dp (Quy hoạch động chữ số)
+ Dp bitmask (Quy hoạch động kết hợp bitmask)
+ Dp matrix multiplication (Quy hoạch động kết hợp nhân ma trận)
+ Dp On Tree (Quy hoạch động trên cây)
+ Knuth Yao Optimize
+ Quy hoạch động bao lồi
+ Quy hoạch động chia để trị
+ Làm kỳ thi

- Tháng 10: Graph advanced


+ Luồng cực đại (max flow)
+ Lát cắt cực tiểu (min - cut problem)
+ Làm thêm bài tập về luồng cực đại + lát cắt cực tiểu
+ Maximum Matching
+ Lowest common Ancestor (LCA)
+ Tree Decomposition
+ Centroid Decomposition
+ Làm kỳ thi

- Tháng 11: Toán nâng cao


+ Định lý thặng dư Trung Hoa (Chinese remainder)
+ Hàm mobius và nghịch đảo Mobius
+ Xích Markov
+ Lý thuyết trò chơi
+ Lý thuyết trò chơi nâng cao
+ DFT
+ FFT
+ Làm kỳ thi
- Tháng 12: Ôn tập lại kiến thức của tất cả.

-----------------------------------------------------------------------------------
-------------------------------------------------

Độ phức tạp thuật toán

Khi ta thiết kế thuật toán. Để giải quyết cùng một vấn đề P, làm sao để có thể đo
lường được thuật toán nào tốt, thuật toán nào chưa tốt

=====> cần đại lượng để đo: Độ phức tạp thuật toán

Một chiếc máy tính bình thường, có thể xử lý tối đa 10 triệu phép tính / giây

Trong lập trình thi đấu, với những đề bài thuật toán, người ta thường giới hạn thời
gian để đưa ra được kết quả. Việc tối ưu về mặt độ phức tạp thuật toán là
ta phải thực hiện một thuật toán sao cho số lượng bước thực thi không vượt quá số
lượng bước có thể cho phép.

Khi đánh giá độ phức tạp thuật toán, ta phải xét thời gian mà thuật toán thực thi
trong trường hợp chậm nhất

Một số độ phức tạp thuật toán THÔNG DỤNG:

O(1): Khi ta thiết kế những thuật toán chỉ chạy trong một vài bước (với số lượng
bước là số nhỏ)

Ví dụ: Kiểm tra N có phải là số chẵn / lẻ, Kiểm tra 3 số a, b, c có phải là độ dài
3 cạnh tam giác hay không ?

O(logN):

for i: 1 -> N, i = i * 2

Nếu N = 5000

i = 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 (dừng)

Nếu N = 10^18 =====> i chỉ thực hiện tầm ~ log(10^18) ~ 63 bước

O(căn(N)): Khi ta thiết kế thuật toán với số bước thực hiện trong căn(N)

Kiểm tra số N có phải số nguyên tố hay không:

for i: 2 -> căn(N)


nếu N chia hết cho i
====> N không phải là số nguyên tố.

Nếu N là số nguyên tố (ví dụ N = 1000000007)

O(N): Khi ta thiết kế thuật toán chạy tuyến tính với số N

for i: 1 -> N
res = res + a[i]

N = 1 triệu =====> i = 1, 2, 3, 4, 5, 6, 7, ...., 1 triệu (chạy 1 triệu bước)

O(N^c): Khi ta thiết kế thuật toán chạy với nhiều vòng lặp tuyến tính LỒNG NHAU:
for i: 1 -> N
for j: N -> 1
for k: 1 -> N

O(N^3)

O(2^n): Đây là độ phức tạp thuật toán xuất hiện khi ta liệt kê tất cả các tập hợp
của một dãy số.

O(n!): Đây là độ phức tạp thuật toán khi ta liệt kê toàn bộ trường hợp có thể xảy
ra.

Một số quy tắc tính độ phức tạp:

1. Quy tắc hằng số:

Nếu thuật toán được hợp bởi nhiều thuật toán nhỏ có độ phức tạp giống nhau thì độ
phức tạp tổng quát sẽ là độ phức tạp của thuật toán nhỏ đó.

for i: 1 -> N
cout << a[i] << ' ';

for i: 1 -> N
cout << b[i] << ' ';

2. Quy tắc cộng:

Nếu thuật toán được hợp bởi nhiều thuật toán có độ phức tạp khác nhau, thì độ phức
tạp thuật toán tổng uqát sẽ được lấy bởi độ phức tạp của thuật toán chạy chậm nhất
trong những thuật toán đã cho

for i: 1 -> N:
cout << a[i] << ' ';

for i: 1 -> N, i = i + 2
for j: N -> 1, j = j - 1
sum = sum + a[i] + a[j]

cout << sum;

3. Quy tắc nhân:

Nếu ta có thuật toán được lồng nhau bởi 2 hoặc nhiều thuật toán thì độ phức tạp
thuật toán tổng quát sẽ bằng tích các độ phức tạp thuật toán thành phần

for i: 1 -> căn (N)


for j: N -> 1, j = j - 1
for k: 1 -> N, k = k * 2

O(căn (N) * N * log(N))

for i: 1 -> N, i = i * 2
for j: 1 -> N, j = j + 1
O(log(N) * N)

Trong Competitive Programming, ta hãy đánh giá độ phức tạp thuật toán làm sao để số
bước thực thi không vượt quá số bước mà đề cho phép.

Thuật toán sắp xếp:

Hàm sort: Đây là hàm sắp xếp các giá trị trong một dãy số theo thứ tự tăng dần
(hoặc theo thứ tự mà người ta mong muốn)

#include <algorithm>

Ta có mảng tĩnh a[100];

Nếu ta muốn sắp xếp tăng dần các phần tử từ vị trí [l .. r]:

sort(a + l, a + r + 1);

Ví dụ:

a = [5, 1, 2, 9, 4, 6, 7, 3, 3, 5, 2, 4, 1]

sort(a + 2, a + 8);

a = [5, 1, 2, 4, 6, 7, 9, 3, 3, 5, 2, 4, 1]

Hàm sắp xếp này có độ phức tạp O(NlogN)

Thuật toán Merge Sort (Sắp xếp trộn)

You might also like