Bỏ qua để đến nội dung

Tổ hợp modulo số nguyên tố nhỏ: Legendre, Kummer, Lucas

Mức độ: Chuyên sâu

Bài Lũy thừa nhanh tính C(n, k) mod p bằng công thức gt[n] × nghịch đảo(gt[k]) × nghịch đảo(gt[n - k]). Cách đó chỉ đúng khi n nhỏ hơn p: nếu n lớn hơn hoặc bằng p thì gt[n] chia hết cho p, mẫu số cũng có thể chia hết cho p, và không có nghịch đảo nào cả. Với p nhỏ (2, 3, 13, 10007) và n đến 1018, cần ba công cụ khác:

  • Công thức Legendre: n! chia hết cho p bao nhiêu lần.
  • Định lý Kummer: C(n, k) chia hết cho p bao nhiêu lần, đọc từ phép cộng trong cơ số p.
  • Định lý Lucas: C(n, k) mod p bằng tích các tổ hợp của từng chữ số trong cơ số p.

Các bạn cần nắm vững bài Lũy thừa nhanh (Fermat nhỏ, nghịch đảo) và bài Định lý số dư Trung Hoa trước khi học bài này.

Số mũ của số nguyên tố p trong n! là

e = n // p + n // p2 + n // p3 + …

Lý do: trong các số từ 1 đến n, có n // p số chia hết cho p, mỗi số góp ít nhất một thừa số p. Có n // p2 số chia hết cho p2, mỗi số góp thêm một thừa số nữa, và cứ thế.

Ví dụ 10! với p = 2: 10 // 2 + 10 // 4 + 10 // 8 = 5 + 2 + 1 = 8. Thật vậy 10! = 3628800 = 28 × 14175.

def legendre(n, p):
"""Số mũ của p trong n!"""
s = 0
while n:
n //= p
s += n
return s
print(legendre(10, 2)) # 8
print(legendre(100, 5)) # 24: 100! có 24 chữ số 0 tận cùng

Chia chính n cho p ở mỗi bước (thay vì tính pi) nên không bao giờ bị tràn số. Số bước khoảng logp(n).

Từ đó, số mũ của p trong C(n, k) = n! / (k! × (n - k)!) là

legendre(n, p) - legendre(k, p) - legendre(n - k, p).

Với p không nguyên tố (ví dụ cơ số 12 = 22 × 3), phân tích ra thừa số nguyên tố, tính cho từng thừa số rồi lấy giá trị nhỏ nhất của (số mũ trong n!) // (số mũ trong cơ số).

Số mũ của p trong C(a + b, a) bằng số lần nhớ khi đặt tính cộng a + b trong cơ số p.

Ví dụ C(10, 3) = 120 = 23 × 15. Cộng 3 + 7 trong cơ số 2:

0 0 1 1 (3)
+ 0 1 1 1 (7)
---------
1 0 1 0 (10)

Nhớ ở bit 0, bit 1, bit 2: đúng 3 lần.

Hệ quả rất hay dùng: cộng n + n trong cơ số 2 thì mỗi bit 1 của n nhớ đúng một lần, nên số mũ của 2 trong C(2n, n) bằng số bit 1 của n.

Viết n và k trong cơ số p: n = (nm … n1 n0), k = (km … k1 k0). Khi đó

C(n, k) ≡ C(nm, km) × … × C(n1, k1) × C(n0, k0) (mod p)

với quy ước C(a, b) = 0 khi b lớn hơn a.

Ví dụ C(10, 3) mod 3: 10 = 101 và 3 = 010 trong cơ số 3. Tích là C(1, 0) × C(0, 1) × C(1, 0) = 1 × 0 × 1 = 0, nên C(10, 3) chia hết cho 3 (thật vậy, 120 = 3 × 40).

Ví dụ C(10, 3) mod 7: 10 = 13 và 3 = 03 trong cơ số 7. Tích là C(1, 0) × C(3, 3) = 1. Thật vậy 120 = 7 × 17 + 1.

Mỗi chữ số đều nhỏ hơn p, nên chỉ cần bảng giai thừa từ 0 đến p - 1, và tổ hợp nhỏ tính bằng nghịch đảo theo Fermat nhỏ như bình thường.

def tao_bang(p):
gt = [1] * p
for i in range(1, p):
gt[i] = gt[i - 1] * i % p
return gt
def c_nho(n, k, p, gt):
"""C(n, k) % p với n, k nhỏ hơn p"""
if k > n:
return 0
return gt[n] * pow(gt[k] * gt[n - k], p - 2, p) % p
def lucas(n, k, p, gt):
kq = 1
while n or k:
kq = kq * c_nho(n % p, k % p, p, gt) % p
if kq == 0:
return 0
n //= p
k //= p
return kq
gt7 = tao_bang(7)
print(lucas(10, 3, 7, gt7)) # 1
print(lucas(10 ** 18, 12345, 7, gt7))

Tạo bảng mất p bước, mỗi lần gọi lucas mất khoảng logp(n) bước. Lucas hợp với p nhỏ (đến khoảng 106, để bảng vừa bộ nhớ). Khi p lớn hơn n, chỉ có một chữ số và Lucas trở về công thức giai thừa thông thường.

Lưu ý: định lý Lucas chỉ đúng khi p là số nguyên tố. Với “cơ số 6”: C(6, 3) = 20 ≡ 2 (mod 6), nhưng tích theo chữ số cơ số 6 là C(1, 0) × C(0, 3) = 0, sai.

Với p = 2, mỗi chữ số là một bit, và C(0, 1) = 0 là trường hợp duy nhất bằng 0. Vậy:

C(n, k) lẻ khi và chỉ khi mọi bit 1 của k cũng là bit 1 của n, tức (n & k) == k.

Kéo theo hàng n của tam giác Pascal có đúng 2(số bit 1 của n) số lẻ. Tô màu các số lẻ của tam giác Pascal, ta được hình tam giác Sierpinski: 2m hàng đầu có đúng 3m số lẻ.

hàng 0: 1
hàng 1: 1 1
hàng 2: 1 . 1
hàng 3: 1 1 1 1
hàng 4: 1 . . . 1
hàng 5: 1 1 . . 1 1
hàng 6: 1 . 1 . 1 . 1
hàng 7: 1 1 1 1 1 1 1 1

(dấu chấm là số chẵn). Ví dụ hàng 6 = 110 có 2 bit 1, nên có 4 số lẻ.

Modulo là tích các số nguyên tố khác nhau

Phần tiêu đề “Modulo là tích các số nguyên tố khác nhau”

Khi modulo m = p1 × p2 × … (các số nguyên tố khác nhau), tính C(n, k) mod pi bằng Lucas cho từng pi, rồi ghép lại bằng định lý số dư Trung Hoa.

Ví dụ C(10, 3) = 120 theo modulo 1001 = 7 × 11 × 13: các số dư là 1, 10, 3, ghép lại được đúng 120.

Nếu m chia hết cho p2 (ví dụ m = 4, 9, 109) thì Lucas không đủ, cần các kỹ thuật khó hơn (định lý Granville). Trong đề thi, modulo thường được chọn là số nguyên tố lớn (109 + 7) hoặc số nguyên tố nhỏ, hoặc tích các số nguyên tố khác nhau như ở đây.

Gồm 20 bài, chia thành 4 nhóm từ dễ đến khó. Mỗi bài có một dữ liệu kiểm tra: các bạn chạy chương trình của mình với dữ liệu đó rồi so với đáp số.

Nhập n và số nguyên tố p (1 ≤ n ≤ 1018, 2 ≤ p ≤ 1018). In ra số mũ lớn nhất e sao cho n! chia hết cho pe.

Ví dụ: nhập 10 2 thì in ra 8.

Kiểm tra: nhập 1000000000000000000 7.

Xem đáp số

166666666666666656

Hướng dẫn giải chi tiết: liên hệ tác giả.

Bài 2. Số chữ số 0 tận cùng trong cơ số b

Phần tiêu đề “Bài 2. Số chữ số 0 tận cùng trong cơ số b”

Nhập n và b (1 ≤ n ≤ 1018, 2 ≤ b ≤ 1012). Viết n! trong hệ cơ số b. In ra số chữ số 0 ở tận cùng.

Ví dụ: nhập 10 12 thì in ra 4.

Kiểm tra: nhập 1000000000000000000 1000000000000.

Xem đáp số

20833333333333332

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập m (1 ≤ m ≤ 1012). In ra số nguyên dương n nhỏ nhất sao cho n! chia hết cho m.

Ví dụ: nhập 12 thì in ra 4.

Kiểm tra: nhập 999999999999.

Xem đáp số

9901

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập n và số nguyên tố p (1 ≤ n ≤ 109, 2 ≤ p ≤ 109). In ra số mũ của p trong tích 1! × 2! × 3! × … × n!.

Ví dụ: nhập 5 2 thì in ra 8.

Kiểm tra: nhập 1000000000 2.

Xem đáp số

499999985653071859

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập n, k và số nguyên tố p (0 ≤ k ≤ n ≤ 1018, 2 ≤ p ≤ 1018). In ra số mũ lớn nhất e sao cho C(n, k) chia hết cho pe.

Ví dụ: nhập 10 3 2 thì in ra 3.

Kiểm tra: nhập 1000000000000000000 123456789012345678 3.

Xem đáp số

21

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhóm 2. Định lý Kummer, chẵn lẻ của tổ hợp

Phần tiêu đề “Nhóm 2. Định lý Kummer, chẵn lẻ của tổ hợp”

Nhập a, b và số nguyên tố p (0 ≤ a, b ≤ 1018, 2 ≤ p ≤ 109). Đặt tính cộng a + b trong hệ cơ số p. In ra số lần phải nhớ.

Ví dụ: nhập 7 5 2 thì in ra 3.

Kiểm tra: nhập 123456789123456789 987654321987654321 10.

Xem đáp số

18

Hướng dẫn giải chi tiết: liên hệ tác giả.

Dòng đầu là T (T ≤ 105), T dòng sau mỗi dòng có n, k (0 ≤ k ≤ n ≤ 1018). Với mỗi dòng in ra LE nếu C(n, k) lẻ, CHAN nếu chẵn.

Ví dụ:

NhậpIn ra
4
4 2
5 1
7 3
6 3
CHAN
LE
LE
CHAN

Kiểm tra: nhập

3
1000000000000000000 0
1000000000000000000 1
1152921504606846975 123456789
Xem đáp số
LE
CHAN
LE

Hướng dẫn giải chi tiết: liên hệ tác giả.

Bài 8. Số lẻ trên một hàng tam giác Pascal

Phần tiêu đề “Bài 8. Số lẻ trên một hàng tam giác Pascal”

Nhập n (0 ≤ n ≤ 1018). Hàng n của tam giác Pascal gồm C(n, 0), C(n, 1), …, C(n, n). In ra số các số lẻ trên hàng đó.

Ví dụ: nhập 6 thì in ra 4.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

16777216

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập n và số nguyên tố p (0 ≤ n ≤ 1018, 2 ≤ p ≤ 109). In ra số các số k từ 0 đến n sao cho C(n, k) không chia hết cho p.

Ví dụ: nhập 10 3 thì in ra 4.

Kiểm tra: nhập 1000000000000000000 7.

Xem đáp số

232243200000

Hướng dẫn giải chi tiết: liên hệ tác giả.

Số Catalan thứ n là Cn = C(2n, n) / (n + 1). Dòng đầu là T (T ≤ 105), T dòng sau mỗi dòng một số n (0 ≤ n ≤ 1018). Với mỗi n in ra LE nếu Cn lẻ, CHAN nếu chẵn.

Ví dụ:

NhậpIn ra
5
0
1
2
3
7
LE
LE
CHAN
LE
LE

Kiểm tra: nhập

4
1000000000000000000
1152921504606846975
576460752303423487
576460752303423488
Xem đáp số
CHAN
LE
LE
CHAN

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập n, k và số nguyên tố p (0 ≤ n, k ≤ 1018, 2 ≤ p ≤ 105). In ra C(n, k) mod p (quy ước C(n, k) = 0 khi k lớn hơn n).

Ví dụ: nhập 10 3 7 thì in ra 1.

Kiểm tra: nhập 999730024299270 123456789012345 99991.

Xem đáp số

99990

Hướng dẫn giải chi tiết: liên hệ tác giả.

Dòng đầu có số nguyên tố p và Q (2 ≤ p ≤ 106, Q ≤ 105). Q dòng sau mỗi dòng có n, k (0 ≤ k ≤ n ≤ 1018). Với mỗi dòng in ra C(n, k) mod p.

Ví dụ:

NhậpIn ra
5 3
10 3
7 2
25 5
0
1
0

Kiểm tra: nhập

999983 3
1000000000000000000 1
1000000000000000000 999999999999
999982 499991
Xem đáp số
4913
400827
999982

Hướng dẫn giải chi tiết: liên hệ tác giả.

Rô-bốt đi từ ô (0, 0) đến ô (a, b), mỗi bước sang phải hoặc lên trên một ô. Nhập a, b (0 ≤ a, b ≤ 1017). In ra số đường đi khác nhau, lấy dư cho 13.

Ví dụ: nhập 2 2 thì in ra 6.

Kiểm tra: nhập 12345678901234567 38840214112856189.

Xem đáp số

12

Hướng dẫn giải chi tiết: liên hệ tác giả.

Chia n viên kẹo giống nhau cho k em (1 ≤ k, 0 ≤ n, n + k ≤ 1018), em nào cũng có thể không được viên nào. In ra số cách chia, lấy dư cho 10007.

Ví dụ: nhập 4 3 thì in ra 15.

Kiểm tra: nhập 10028029290265611 123456790.

Xem đáp số

10006

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhập n (0 ≤ n ≤ 1018). Trên hàng n của tam giác Pascal, đếm số các số chia 3 dư 1 và số các số chia 3 dư 2. In ra hai số đó.

Ví dụ: nhập 5 thì in ra 4 2.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

7346640896 7346639872

Hướng dẫn giải chi tiết: liên hệ tác giả.

Nhóm 4. Modulo hợp số và đếm trên tam giác Pascal

Phần tiêu đề “Nhóm 4. Modulo hợp số và đếm trên tam giác Pascal”

Nhập n, k (0 ≤ k ≤ n ≤ 1018). In ra C(n, k) mod 6.

Ví dụ: nhập 10 3 thì in ra 0.

Kiểm tra: nhập 1152921504606846975 123456789.

Xem đáp số

3

Hướng dẫn giải chi tiết: liên hệ tác giả.

Bài 17. Modulo là tích các số nguyên tố khác nhau

Phần tiêu đề “Bài 17. Modulo là tích các số nguyên tố khác nhau”

Nhập n, k, m (0 ≤ k ≤ n ≤ 1018, 2 ≤ m ≤ 109). Biết m là tích của các số nguyên tố khác nhau, mỗi số không quá 105. In ra C(n, k) mod m.

Ví dụ: nhập 10 3 1001 thì in ra 120.

Kiểm tra: nhập 1000000000000000000 123456789012 997210243.

Xem đáp số

559755856

Hướng dẫn giải chi tiết: liên hệ tác giả.

Bài 18. Đếm số lẻ trong cả tam giác Pascal

Phần tiêu đề “Bài 18. Đếm số lẻ trong cả tam giác Pascal”

Nhập N (1 ≤ N ≤ 1018). Đếm số cặp (n, k) với 0 ≤ k ≤ n nhỏ hơn N mà C(n, k) lẻ, tức số các số lẻ trên N hàng đầu của tam giác Pascal. In ra kết quả mod 109 + 7.

Ví dụ: nhập 4 thì in ra 9.

Kiểm tra: nhập 1000000000000000000.

Xem đáp số

119299987

Hướng dẫn giải chi tiết: liên hệ tác giả.

Bài 19. Đếm số chia hết cho p trong tam giác Pascal

Phần tiêu đề “Bài 19. Đếm số chia hết cho p trong tam giác Pascal”

Nhập N và số nguyên tố p (1 ≤ N ≤ 1018, 2 ≤ p ≤ 109). Đếm số cặp (n, k) với 0 ≤ k ≤ n nhỏ hơn N mà C(n, k) chia hết cho p. In ra kết quả mod 109 + 7.

Ví dụ: nhập 10 3 thì in ra 17.

Kiểm tra: nhập 1000000000000000000 7.

Xem đáp số

766734713

Hướng dẫn giải chi tiết: liên hệ tác giả.

Bài 20. Lũy thừa lớn nhất của m chia hết C(n, k)

Phần tiêu đề “Bài 20. Lũy thừa lớn nhất của m chia hết C(n, k)”

Nhập n, k, m (0 ≤ k ≤ n ≤ 1018, 2 ≤ m ≤ 1012). In ra số mũ lớn nhất e sao cho C(n, k) chia hết cho me. Ví dụ với m = 10, đó là số chữ số 0 tận cùng của C(n, k).

Ví dụ: nhập 100 50 10 thì in ra 0.

Kiểm tra: nhập 1000000000000000000 500000000000000001 1000000000000.

Xem đáp số

1

Hướng dẫn giải chi tiết: liên hệ tác giả.