II. Các dãy số và công thức quan trọng
1. Dãy Fibonaci
Dãy số Fibonaci được xác định bởi công thức sau:
Một số phần tử đầu tiên của dãy Fibonaci là: Ngoài ra, số Fibonaci thứ còn có thể tính bằng công thức tổng quát:
Dãy Fibonaci là đáp án của một số bài toán dưới đây:
1.1. Bài toán cổ về các cặp thỏ:
- Phát biểu bài toán:
- Ban đầu chỉ có một cặp thỏ được sinh ra.
- Hai tháng sau khi ra đời, mỗi cặp thỏ sẽ sinh ra một cặp thỏ con mới.
- Khi đã sinh con rồi thì cứ mỗi tháng tiếp theo, chúng lại sinh được một cặp con mới.
- Giả sử các con thỏ không bao giờ chết, hãy đếm số lượng cặp thỏ ở tháng thứ
- Ví dụ: Với ta thấy:
- Giải thích:
- Giữa tháng thứ nhất: cặp (cặp ban đầu).
- Giữa tháng thứ hai: cặp (cặp ban đầu vẫn chưa đẻ).
- Giữa tháng thứ ba: cặp (cặp ban đầu đẻ thêm một cặp con).
- Giữa tháng thứ tư: cặp (cặp ban đầu tiếp tục đẻ).
- Giữa tháng thứ năm: cặp (cặp ban đầu tiếp tục đẻ và cặp thứ hai bắt đầu đẻ).
1.2. Bài toán xếp Domino:
- Phát biểu bài toán: Đếm số cách xếp thanh Domino có kích thước để phủ kín một bảng ô vuông kích thước .
- Ví dụ: Có cách khác nhau để xếp các thanh Domino kích thước phủ kín bảng :
1.3. Cài đặt:
- Đối với các giá trị không quá lớn, ta có thể tính trực tiếp số Fibonaci bằng công thức truy hồi . Trong trường hợp lớn, cần phải sử dụng Phép nhân ma trận để tính toán, bài toán này sẽ được đề cập tới sau.
- Cài đặt bằng công thức truy hồi:
long long fibo(int N) { if (N <= 1) return N; int fi_2 = 0, fi_1 = 1, cur_fi = 0; for (int i = 2; i <= N; ++i) { cur_fi = fi_1 + fi_2; fi_2 = fi_1; fi_1 = cur_fi; } return fi_ntext; }
2. Dãy Catalan:
- Số Catalan được xác định bởi công thức sau:
- Một số phần tử đầu tiên của dãy Catalan là:
- Số Catalan là đáp án của các bài toán sau:
2.1. Bài toán đặt ngoặc:
- Phát biểu bài toán: Cho trước số nguyên không âm hãy đếm số cách khác nhau để đặt dấu ngoặc mở và dấu ngoặc đóng đúng đắn. Cách đặt ngoặc đúng đắn có thể phát biểu đệ quy như sau:
- là một cách đặt ngoặc đúng.
- Nếu là một cách đặt ngoặc đúng thì và cũng là cách đặt ngoặc đúng.
- Ví dụ: Với ta có cách đặt ngoặc đúng sau:
2.2. Đếm cây nhị phân:
- Phát biểu bài toán: Cho trước số nguyên không âm N, hãy đếm số cây nhị phân khác nhau có đúng lá?
- Ví dụ: Với :
2.3. Chia đa giác:
- Phát biểu bài toán: Cho một đa giác lồi gồm đỉnh. Ta chia đa giác thành các tam giác bằng cách vẽ các đường chéo không cắt nhau trong đa giác. Hỏi có bao nhiêu cách chia như vậy:
- Ví dụ: Với :
2.4. Cài đặt:
- Dưới đây cài đặt chương trình tính số Catalan thứ và đưa ra kết quả là phần dư sau khi chia cho :
long long modular_exponentiation(long long A, long long B, long long M) { if (B == 0) return 1LL; long long half = modular_exponentiation(A, B / 2LL, M) % M; if (B & 1) return (((half * half) % M) * (A % M)) % M; else return (half * half) % M; } long long inverse_modulo(long long A, long long M) { return modular_exponentiation(A, M - 2, M); } long long catalan_N(long long N, long long M) { long long x = 1, y = 1; for (int i = N + 2; i <= 2 * N; ++i) x = (x * i) % M; for (int i = 1; i <= N; ++i) y = (y * i) % M; y = inverse_modulo(y, M); return (x * y) % M; } int main() { long long M = 1e9 + 7; cout << catalan_N(N, M); }
3. Số Euler (Eulerian Number):
- Số Euler là số lượng hoán vị của các số từ tới mà có đúng số lớn hơn số đứng liền trước nó. Lấy ví dụ, với có hoán vị từ tới mà có đúng số lớn hơn số liền trước nó, thể hiện trong bảng dưới đây:
- Số Euler là hệ số của đa thức Euler bậc với công thức:
- Ta có thể tính số Euler bằng hệ thức truy hồi sau:
- Cài đặt: Dưới đây cài đặt chương trình tính số Euler bằng đệ quy, ngoài ra bạn đọc có thể suy nghĩ cách cài đặt bằng quy hoạch động:
long long euler_number(int N, int M) { if (M == 0) return 1; if (M >= N || N == 0) return 0; return (N - M) * euler_number(N - 1, M - 1) + (M + 1) * euler_number(N - 1, M); }
4. Tam giác Pascal:
- Tam giác Pascal là một công thức xác định các tổ hợp chập của bằng tính chất của tổ hợp: . Quy ước hàng đầu tiên của tam giác là có duy nhất một số - để biểu thị cho . Sử dụng công thức truy hồi, chúng ta dễ dàng tính được tam giác Pascal với vị trí hàng cột là số lượng tổ hợp chập của (coi các vị trí trống là 0). Ở mỗi hàng, cột đầu tiên và cột cuối cùng luôn mang giá trị thể hiện cho tính chất . Hình vẽ dưới đây minh họa cho tam giác Pascal với các hàng từ tới :
- Ngoài ra, tam giác Pascal còn sử dụng để tính các hệ số của khai triển nhị thức Newton bậc thành một đa thức có số hạng. Nhị thức này đã được chứng minh bởi Issac Newton vào năm với công thức như sau:
- Cài đặt: Xây dựng tam giác Pascal gồm hàng:
void pascal_triangle(int N) { for (int i = 0; i <= N; ++i) // Cột đầu tiên của mọi hàng bằng 1. c[i][0] = 1; for (int i = 1; i <= N; ++i) for (int j = 1; j <= i; ++j) c[i][j] = c[i - 1][j - 1] + c[i - 1][j]; }
5. Công thức bao hàm - loại trừ:
- Công thức bao hàm - loại trừ là một công thức sử dụng để tính lực lượng (số lượng phần tử) của hợp của nhiều tập hợp. Công thức được phát biểu như sau: "Để tính lực lượng của hợp của nhiều tập hợp, ta tính tổng lực lượng các tập hợp đó, rồi trừ đi lực lượng của giao của các cặp hai tập hợp khác nhau, rồi cộng lực lượng của giao các bộ ba tập hợp khác nhau, rồi trừ đi lực lượng của các bộ bốn tập hợp, và cứ thế cho đến khi ta xét đến giao của tất cả các tập hợp."
- Đối với các tập hợp, công thức có thể được viết ở dạng như sau: Giả sử có tập hợp . Lực lượng của hợp của tập hợp là:
- Ta có thể minh họa công thức bằng một sơ đồ Venn trong trường hợp như sau:
Như sơ đồ, ta thấy lực lượng của bằng tổng lực lượng của trừ đi lực lượng của các giao rồi cộng thêm lực lượng của :
Bằng phương pháp tương tự ta có thể minh họa được công thức với tập hợp.
- Ví dụ: Đếm số lượng số từ tới và không chia hết cho số nào trong tập :
Ta có thể biến đổi bài toán thành đếm phần bù: Đếm số lượng phần tử chia hết cho ít nhất một số trong tập rồi lấy trừ đi số lượng đó. Đặt là tập hợp các phần tử chia hết cho là tập hợp các phần tử chia hết cho là tập hợp các phần tử chia hết cho từ 1 tới . Cần tính . Dựa vào công thức bao hàm, loại trừ, ta có:int count_numbers(int N) { return N - N / 2 - N / 3 - N / 5 + N / (2 * 3) + N / (3 * 5) + N / (2 * 5) - N / (2 * 3 * 5); }