Định lý số dư Trung Hoa
Bài toán cổ Hàn Tín điểm binh: cho quân xếp hàng 3 thì thừa 2 người, xếp hàng 5 thì thừa 3 người, xếp hàng 7 thì thừa 2 người. Hỏi có ít nhất bao nhiêu quân?
Viết theo đồng dư, cần tìm x sao cho
- x ≡ 2 (mod 3)
- x ≡ 3 (mod 5)
- x ≡ 2 (mod 7)
Định lý số dư Trung Hoa nói rằng: nếu các modulo đôi một nguyên tố cùng nhau thì hệ luôn có nghiệm, và các nghiệm cách nhau đúng tích các modulo (ở đây 3 × 5 × 7 = 105). Đáp số là 23 (rồi 128, 233, …).
Các bạn cần nắm vững bài Đồng dư và bài Thuật toán Euclid mở rộng trước khi học bài này.
Cách 1. Thử dần
Phần tiêu đề “Cách 1. Thử dần”Chỉ cần thử các số thỏa mãn đồng dư có modulo lớn nhất: 2, 9, 16, 23, … (thỏa mãn x ≡ 2 (mod 7)), rồi kiểm tra hai đồng dư còn lại.
| x | x % 3 | x % 5 |
|---|---|---|
| 2 | 2 | 2 |
| 9 | 0 | 4 |
| 16 | 1 | 1 |
| 23 | 2 | 3 |
Cách này cần thử tới m1 × m2 × … chia cho modulo lớn nhất số, chỉ dùng được khi các modulo nhỏ.
Cách 2. Ghép từng cặp đồng dư
Phần tiêu đề “Cách 2. Ghép từng cặp đồng dư”Ghép hai đồng dư đầu thành một đồng dư, rồi ghép tiếp với đồng dư thứ ba, cứ thế đến hết.
Ghép x ≡ r1 (mod m1) với x ≡ r2 (mod m2): từ đồng dư thứ nhất, x = r1 + m1 × t. Thay vào đồng dư thứ hai:
m1 × t ≡ r2 - r1 (mod m2)
Đây là phương trình đồng dư đã giải ở bài Euclid mở rộng. Đặt g = ƯCLN(m1, m2):
- Nếu r2 - r1 không chia hết cho g: hệ vô nghiệm.
- Ngược lại: t = (r2 - r1) / g × p % (m2 / g), với p là hệ số Bézout của m1 (m1 × p + m2 × q = g). Hai đồng dư gộp thành x ≡ r1 + m1 × t (mod BCNN(m1, m2)).
Cách này dùng được cả khi các modulo không nguyên tố cùng nhau. Chạy với bài Hàn Tín:
| Ghép | g | t | Kết quả |
|---|---|---|---|
| x ≡ 2 (mod 3) với x ≡ 3 (mod 5) | 1 | 2 | x ≡ 2 + 3 × 2 = 8 (mod 15) |
| x ≡ 8 (mod 15) với x ≡ 2 (mod 7) | 1 | 1 | x ≡ 8 + 15 × 1 = 23 (mod 105) |
def euclid_mo_rong(a, b): if b == 0: return a, 1, 0 g, x1, y1 = euclid_mo_rong(b, a % b) return g, y1, x1 - (a // b) * y1
def ghep(r1, m1, r2, m2): """Gộp x ≡ r1 (mod m1) và x ≡ r2 (mod m2) thành (r, m); None nếu vô nghiệm.""" g, p, _ = euclid_mo_rong(m1, m2) if (r2 - r1) % g != 0: return None m2g = m2 // g t = (r2 - r1) // g * p % m2g m = m1 * m2g # BCNN(m1, m2) return (r1 + m1 * t) % m, m
r, m = 0, 1 # x ≡ 0 (mod 1): mọi sốfor mi, ri in [(3, 2), (5, 3), (7, 2)]: r, m = ghep(r, m, ri, mi)print(r, m) # 23 105#include <iostream>using namespace std;
long long euclidMoRong(long long a, long long b, long long &x, long long &y) { if (b == 0) { x = 1; y = 0; return a; } long long x1, y1; long long g = euclidMoRong(b, a % b, x1, y1); x = y1; y = x1 - (a / b) * y1; return g;}
// Gộp x ≡ r1 (mod m1) và x ≡ r2 (mod m2) thành x ≡ r (mod m); false nếu vô nghiệm.// Giả sử BCNN không vượt quá 10^18; dùng __int128 khi nhân để không tràn.bool ghep(long long r1, long long m1, long long r2, long long m2, long long &r, long long &m) { long long p, q; long long g = euclidMoRong(m1, m2, p, q); if ((r2 - r1) % g != 0) return false; long long m2g = m2 / g; __int128 t = (__int128)((r2 - r1) / g % m2g) * (p % m2g) % m2g; if (t < 0) t += m2g; m = m1 * m2g; r = (long long)(((__int128)r1 + (__int128)m1 * t) % m); return true;}
int main() { long long r = 0, m = 1; long long cacM[3] = {3, 5, 7}, cacR[3] = {2, 3, 2}; for (int i = 0; i < 3; i++) ghep(r, m, cacR[i], cacM[i], r, m); cout << r << " " << m << endl; // 23 105 return 0;}Lưu ý về tràn số: modulo sau khi gộp có thể tới 1018, và m1 × t có thể
vượt long long. Trong C++ phải nhân bằng __int128 như hàm trên. Python không bị tràn số.
Lưu ý về điểm bắt đầu: gộp bắt đầu từ x ≡ 0 (mod 1), tức “mọi số nguyên”. Như vậy không cần xử lý riêng đồng dư đầu tiên.
Khi các modulo không nguyên tố cùng nhau
Phần tiêu đề “Khi các modulo không nguyên tố cùng nhau”x ≡ 5 (mod 12) và x ≡ 11 (mod 18): g = 6, và 11 - 5 = 6 chia hết cho 6, nên có nghiệm: x ≡ 29 (mod 36). Thử lại: 29 = 2 × 12 + 5 = 18 + 11.
x ≡ 1 (mod 4) và x ≡ 2 (mod 6): g = 2, 2 - 1 = 1 không chia hết cho 2, vô nghiệm. Dễ thấy vì đồng dư thứ nhất bắt x lẻ, đồng dư thứ hai bắt x chẵn.
Công thức khi các modulo nguyên tố cùng nhau
Phần tiêu đề “Công thức khi các modulo nguyên tố cùng nhau”Khi các modulo đôi một nguyên tố cùng nhau, đặt M = m1 × m2 × … × mk và Mi = M / mi. Gọi yi là nghịch đảo của Mi theo modulo mi. Khi đó
x = (r1 × M1 × y1 + … + rk × Mk × yk) % M
Mỗi số hạng ri × Mi × yi chia mi dư ri và chia hết cho mọi modulo khác. Với bài Hàn Tín: M = 105, ba số hạng là 2 × 35 × 2, 3 × 21 × 1, 2 × 15 × 1, tổng 233 ≡ 23 (mod 105).
Công thức đẹp nhưng chỉ dùng được khi các modulo nguyên tố cùng nhau. Khi lập trình, cách ghép từng cặp an toàn hơn.
Luyện tập
Phần tiêu đề “Luyện tập”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óm 1. Hai đồng dư
Phần tiêu đề “Nhóm 1. Hai đồng dư”Bài 1. Thử dần
Phần tiêu đề “Bài 1. Thử dần”Nhập bốn số r1, m1, r2, m2 (1 ≤ m1, m2 ≤ 1000, 0 ≤ r1 nhỏ hơn m1, 0 ≤ r2 nhỏ hơn m2). In ra số x ≥ 0 nhỏ nhất sao cho x chia m1 dư r1 và chia m2 dư r2, hoặc -1 nếu không có.
Ví dụ: nhập 2 3 3 5 thì in ra 8.
Kiểm tra: nhập 17 101 45 997.
Bài 2. Hai modulo nguyên tố cùng nhau
Phần tiêu đề “Bài 2. Hai modulo nguyên tố cùng nhau”Nhập r1, m1, r2, m2 (1 ≤ m1, m2 ≤ 109, ƯCLN(m1, m2) = 1, 0 ≤ ri nhỏ hơn mi). In ra số x ≥ 0 nhỏ nhất thỏa mãn x ≡ r1 (mod m1) và x ≡ r2 (mod m2).
Ví dụ: nhập 2 3 3 5 thì in ra 8.
Kiểm tra: nhập 123456 999999937 654321 1000000007.
Bài 3. Hai modulo bất kỳ
Phần tiêu đề “Bài 3. Hai modulo bất kỳ”Nhập r1, m1, r2, m2 (1 ≤ m1, m2 ≤ 109, 0 ≤ ri nhỏ hơn mi). In ra số x ≥ 0 nhỏ nhất thỏa mãn hai đồng dư, hoặc -1 nếu vô nghiệm. Các modulo không nhất thiết nguyên tố cùng nhau.
Ví dụ: nhập 5 12 11 18 thì in ra 29.
Kiểm tra: nhập 123456789 999999000 999789 1000000.
Bài 4. Đếm số thỏa mãn hai đồng dư
Phần tiêu đề “Bài 4. Đếm số thỏa mãn hai đồng dư”Nhập r1, m1, r2, m2, N (1 ≤ mi ≤ 109, 0 ≤ ri nhỏ hơn mi, 1 ≤ N ≤ 1018). Có bao nhiêu số x từ 1 đến N thỏa mãn x ≡ r1 (mod m1) và x ≡ r2 (mod m2)?
Ví dụ: nhập 2 3 3 5 100 thì in ra 7.
Kiểm tra: nhập 5 12 11 18 1000000.
Bài 5. Số thứ k
Phần tiêu đề “Bài 5. Số thứ k”Nhập r1, m1, r2, m2, k (1 ≤ mi ≤ 106, 0 ≤ ri nhỏ hơn mi, 1 ≤ k ≤ 106). In ra số nguyên dương thứ k (theo thứ tự tăng dần) thỏa mãn hai đồng dư, hoặc -1 nếu không có số nào.
Ví dụ: nhập 2 3 3 5 2 thì in ra 23.
Kiểm tra: nhập 5 12 11 18 1000.
Nhóm 2. Nhiều đồng dư
Phần tiêu đề “Nhóm 2. Nhiều đồng dư”Bài 6. Hàn Tín điểm binh
Phần tiêu đề “Bài 6. Hàn Tín điểm binh”Có ba dòng, mỗi dòng hai số m, r (1 ≤ m ≤ 100, 0 ≤ r nhỏ hơn m): xếp quân thành hàng m thì thừa r người. In ra số quân ít nhất có thể (một số ≥ 0), hoặc -1 nếu không thể xảy ra.
Ví dụ:
| Nhập | In ra |
|---|---|
3 25 37 2 | 23 |
Kiểm tra: nhập
7 311 513 9Bài 7. Nhiều modulo nguyên tố cùng nhau
Phần tiêu đề “Bài 7. Nhiều modulo nguyên tố cùng nhau”Dòng đầu là n (1 ≤ n ≤ 20). n dòng sau, mỗi dòng hai số mi, ri (mi ≥ 1, 0 ≤ ri nhỏ hơn mi), các mi đôi một nguyên tố cùng nhau và tích của chúng không vượt quá 1018. In ra số x ≥ 0 nhỏ nhất thỏa mãn mọi đồng dư.
Ví dụ:
| Nhập | In ra |
|---|---|
33 25 37 2 | 23 |
Kiểm tra: nhập
51000003 17999983 5101 10097 389 88Bài 8. Nhiều modulo bất kỳ
Phần tiêu đề “Bài 8. Nhiều modulo bất kỳ”Dòng đầu là n (1 ≤ n ≤ 105). n dòng sau, mỗi dòng hai số mi, ri (1 ≤ mi ≤ 109, 0 ≤ ri nhỏ hơn mi). Biết BCNN của mọi mi không vượt quá 1018. In ra số x ≥ 0 nhỏ nhất thỏa mãn mọi đồng dư, hoặc -1 nếu vô nghiệm.
Ví dụ:
| Nhập | In ra |
|---|---|
34 36 59 8 | 35 |
Kiểm tra: nhập
612 918 930 945 91000 789999 369Bài 9. Đếm trong một đoạn
Phần tiêu đề “Bài 9. Đếm trong một đoạn”Dòng đầu là n, L, R (1 ≤ n ≤ 105, 1 ≤ L ≤ R ≤ 1018). n dòng sau, mỗi dòng hai số mi, ri như bài 8. Có bao nhiêu số x từ L đến R thỏa mãn mọi đồng dư?
Ví dụ:
| Nhập | In ra |
|---|---|
2 1 1003 25 3 | 7 |
Kiểm tra: nhập
3 1 10000000000006 110 715 7Bài 10. Hệ có hệ số
Phần tiêu đề “Bài 10. Hệ có hệ số”Dòng đầu là n (1 ≤ n ≤ 10). n dòng sau, mỗi dòng ba số ai, bi, mi (0 ≤ ai, bi nhỏ hơn mi, 1 ≤ mi ≤ 106), nghĩa là ai × x ≡ bi (mod mi). Biết BCNN của mọi mi không vượt quá 1018. In ra số x ≥ 0 nhỏ nhất thỏa mãn cả hệ, hoặc -1.
Ví dụ:
| Nhập | In ra |
|---|---|
22 1 33 4 5 | 8 |
Kiểm tra: nhập
36 4 104 3 75 2 9Nhóm 3. Bài toán thực tế
Phần tiêu đề “Nhóm 3. Bài toán thực tế”Bài 11. Ba ngọn đèn
Phần tiêu đề “Bài 11. Ba ngọn đèn”Ba ngọn đèn nhấp nháy. Đèn thứ i lóe sáng lần đầu ở giây ti, sau đó cứ pi giây lại lóe sáng một lần. Có ba dòng, mỗi dòng hai số ti, pi (0 ≤ ti ≤ 106, 1 ≤ pi ≤ 106). In ra giây đầu tiên cả ba đèn cùng lóe sáng, hoặc -1 nếu không bao giờ.
Ví dụ:
| Nhập | In ra |
|---|---|
2 33 52 7 | 23 |
Kiểm tra: nhập
100 124 1840 45Bài 12. Năm can chi
Phần tiêu đề “Bài 12. Năm can chi”Năm âm lịch được gọi bằng một can (Giáp, Ất, Bính, Đinh, Mậu, Kỷ, Canh, Tân, Nhâm, Quý, lặp lại sau 10 năm) và một chi (Tý, Sửu, Dần, Mão, Thìn, Tỵ, Ngọ, Mùi, Thân, Dậu, Tuất, Hợi, lặp lại sau 12 năm). Năm 1984 là năm Giáp Tý, năm 1985 là Ất Sửu, và cứ thế. Nhập tên can, tên chi và một năm L (1 ≤ L ≤ 109). In ra năm nhỏ nhất từ L trở đi có can chi đó, hoặc -1 nếu không có năm nào như vậy.
Ví dụ: nhập Bính Ngọ 2000 thì in ra 2026.
Kiểm tra: nhập Giáp Tý 2026.
Bài 13. Ba số liên tiếp
Phần tiêu đề “Bài 13. Ba số liên tiếp”Nhập ba số nguyên dương a, b, c (a, b, c ≤ 106). Tìm số nguyên dương x nhỏ nhất sao cho x chia hết cho a, x + 1 chia hết cho b và x + 2 chia hết cho c. In ra -1 nếu không có.
Ví dụ: nhập 2 3 5 thì in ra 8.
Kiểm tra: nhập 7 11 13.
Bài 14. Thỏa mãn ít nhất một
Phần tiêu đề “Bài 14. Thỏa mãn ít nhất một”Nhập r1, m1, r2, m2, N (1 ≤ mi ≤ 109, 0 ≤ ri nhỏ hơn mi, 1 ≤ N ≤ 1018). Có bao nhiêu số x từ 1 đến N thỏa mãn ít nhất một trong hai đồng dư x ≡ r1 (mod m1), x ≡ r2 (mod m2)?
Ví dụ: nhập 2 3 3 5 30 thì in ra 14.
Kiểm tra: nhập 5 12 11 18 1000000.
Bài 15. Hai dãy tuần hoàn
Phần tiêu đề “Bài 15. Hai dãy tuần hoàn”Dãy A gồm n số A0, …, An-1 được viết lặp lại mãi: A0, A1, …, An-1, A0, A1, … Dãy B gồm m số cũng được viết lặp lại như vậy. Dòng đầu là n, m (1 ≤ n, m ≤ 300), hai dòng sau là các số của A và B (không quá 109). Tìm vị trí i ≥ 0 nhỏ nhất mà phần tử thứ i của hai dãy bằng nhau (vị trí đầu tiên là 0). In ra -1 nếu không có.
Ví dụ:
| Nhập | In ra |
|---|---|
3 41 2 34 5 6 3 | 11 |
Kiểm tra: nhập
6 81 3 5 5 1 28 2 8 7 3 8 7 5Bài 16. Thừa và thiếu
Phần tiêu đề “Bài 16. Thừa và thiếu”Dòng đầu là n, L, R (1 ≤ n ≤ 10, 1 ≤ L ≤ R ≤ 1012). n dòng sau có dạng m thừa r (xếp hàng m thì thừa r người) hoặc m thiếu r (xếp hàng m thì hàng cuối thiếu r người), với 2 ≤ m ≤ 1000, 0 ≤ r nhỏ hơn m. In ra số quân nhỏ nhất trong đoạn từ L đến R, hoặc -1 nếu không có.
Ví dụ:
| Nhập | In ra |
|---|---|
3 1000 11003 thừa 25 thừa 37 thiếu 5 | 1073 |
Kiểm tra: nhập
4 2000 50005 thiếu 16 thừa 57 thiếu 311 thừa 1Nhóm 4. Số rất lớn
Phần tiêu đề “Nhóm 4. Số rất lớn”Bài 17. Nhân theo modulo lớn
Phần tiêu đề “Bài 17. Nhân theo modulo lớn”Dòng đầu là n, m (1 ≤ n ≤ 105, 2 ≤ m ≤ 1018). Dòng thứ hai có n số nguyên dương không quá 1018. In ra tích của n số chia lấy dư cho m.
Ví dụ:
| Nhập | In ra |
|---|---|
3 10000000000000000001000000000 1000000000 7 | 0 |
Kiểm tra: nhập
6 999999999999999989376625161664043530 808129322734854035 227670544625192561 618416730735372602 889956528077943303 883282125704228471Bài 18. Lũy thừa theo modulo là tích hai số nguyên tố
Phần tiêu đề “Bài 18. Lũy thừa theo modulo là tích hai số nguyên tố”Gọi P = 1000000007 × 998244353 (cả hai đều là số nguyên tố). Nhập n (0 ≤ n ≤ 1018). In ra 2n chia lấy dư cho P.
Ví dụ: nhập 10 thì in ra 1024.
Kiểm tra: nhập 1000000000000000000.
Bài 19. Nghiệm rất lớn: thuật toán Garner
Phần tiêu đề “Bài 19. Nghiệm rất lớn: thuật toán Garner”Dòng đầu là n (1 ≤ n ≤ 1000). n dòng sau, mỗi dòng hai số mi, ri (2 ≤ mi ≤ 2 × 109, 0 ≤ ri nhỏ hơn mi), các mi đôi một nguyên tố cùng nhau. Gọi x là số ≥ 0 nhỏ nhất thỏa mãn mọi đồng dư (x có thể có hàng nghìn chữ số). In ra x chia lấy dư cho 109 + 7.
Ví dụ:
| Nhập | In ra |
|---|---|
33 25 37 2 | 23 |
Kiểm tra: nhập
5998244353 3374052511000000009 225727008999999937 426508939754974721 270060143167772161 93323692Bài 20. Hệ có nghiệm không
Phần tiêu đề “Bài 20. Hệ có nghiệm không”Dòng đầu là n (1 ≤ n ≤ 105). n dòng sau, mỗi dòng hai số mi, ri (1 ≤ mi ≤ 106, 0 ≤ ri nhỏ hơn mi). Hệ đồng dư có nghiệm không? In ra CÓ hoặc KHÔNG. (BCNN của các mi có thể rất lớn.)
Ví dụ:
| Nhập | In ra |
|---|---|
34 16 39 7 | KHÔNG |
Kiểm tra: nhập
40974461 251621373962 132656844248 837032394627 82308782208 55424538537 302608668697 38233180029 13131758239 249294356931 972294022 24830584531 126186564203 464687306313 205644301574 56796479670 420404147734 106242919052 86752676118 390258738173 386703751217 622578605474 494640324010 18633425943 7808888978 303518745395 467024386763 175382381203 228338483471 217262442729 32198495091 68648418146 194732934250 682084614171 25994581383 557960522670 450494909353 158606122106 260446111 37053530957 106384