Wiki › Thuật toán › Toán học

Toán học

huunguyen huunguyen Updated Tháng 10. 4, 2026 Đọc 8 phút 7 lượt xem

Số nguyên tố

bool is_prime(long long n) {
    if (n<2) return false;
    for (long long i=2; i*i<=n; i++) if (n%i==0) return false;
    return true;
}

// Sàng Eratosthenes: O(N log log N)
vector<bool> sieve(int n) {
    vector<bool> p(n+1,true); p[0]=p[1]=false;
    for (int i=2; i*i<=n; i++) if (p[i]) for (int j=i*i; j<=n; j+=i) p[j]=false;
    return p;
}
def is_prime(n):
    if n < 2: return False
    for i in range(2, int(n**0.5)+1):
        if n % i == 0: return False
    return True

GCD và LCM

#include <numeric>
int g = gcd(a, b);
int l = lcm(a, b);
from math import gcd
g = gcd(a, b)
l = a * b // gcd(a, b)
Cấu trúc ước/bội theo số mũ (dàn gcd/lcm)

Viết a=∏pαp, b=∏pβp. Khi đó với từng thừa số nguyên tố p độc lập:

vp(gcd(a,b))=min(αp,βp),vp(lcm(a,b))=max(αp,βp)

Hệ quả hay dùng:

  • gcd(a,b)·lcm(a,b)=a·b (vì min+max=α+β).
  • a∣b⟺αp≤βp với mọi p; gcd và lcm phân phối với nhau: gcd(x,lcm(y,z))=lcm(gcd(x,y),gcd(x,z)) (vì min/max phân phối trên từng số mũ).
  • Đếm cặp có thứ tự (a,b) với gcd=g, lcm=l: cần g∣l (nếu không thì 0 cặp). Với mỗi p có vp(g)<vp(l), một số nhận số mũ vp(g), số kia nhận vp(l): 2 cách; nếu vp(g)=vp(l) thì chỉ 1 cách. Vậy đáp án là 2k với k là số ước nguyên tố phân biệt của l/g. Ví dụ g=2, l=60: l/g=30=2·3·5 nên có 23=8 cặp.

Đề VOI: Chìa khóa mã số (voi15_crypt) (Kỳ cựu) VOI 2015: tập đóng dưới gcd/lcm, dùng luật phân phối và min/max số mũ (không phải bài đếm cặp); xét riêng từng số nguyên tố p của k (với e=vp(k) là số mũ của p trong k).

Modular Arithmetic

const long long MOD = 1e9+7;
(a+b)%MOD
(a-b+MOD)%MOD
a*b%MOD

// Lũy thừa nhanh O(log n)
long long power(long long a, long long n, long long mod) {
    long long res=1; a%=mod;
    while (n>0) { if (n&1) res=res*a%mod; a=a*a%mod; n>>=1; }
    return res;
}

// Nghịch đảo modulo (mod nguyên tố)
long long inv(long long a) { return power(a, MOD-2, MOD); }
pow(a, n, mod)  # lũy thừa nhanh built-in

Tổ hợp C(n,k)modp

Chi tiết (Pascal, chia kẹo, Catalan, modulo hợp số): xem trang Tổ hợp và đếm cơ bản.

const int MAXN=1e6+5;
long long fact[MAXN], inv_fact[MAXN];
void precompute() {
    fact[0]=1;
    for (int i=1; i<MAXN; i++) fact[i]=fact[i-1]*i%MOD;
    inv_fact[MAXN-1]=power(fact[MAXN-1],MOD-2,MOD);
    for (int i=MAXN-2; i>=0; i--) inv_fact[i]=inv_fact[i+1]*(i+1)%MOD;
}
long long C(int n,int k) {
    if (k<0||k>n) return 0;
    return fact[n]*inv_fact[k]%MOD*inv_fact[n-k]%MOD;
}
from math import comb
print(comb(10, 3))  # C(10,3) = 120

Phân tích thừa số nguyên tố

map<int,int> factorize(int n) {
    map<int,int> f;
    for (int i=2; i*i<=n; i++) while (n%i==0) { f[i]++; n/=i; }
    if (n>1) f[n]++;
    return f;
}

Thuật toán Euclid mở rộng

Tìm x,y sao cho ax+by=gcd(a,b). Chi tiết (Bézout, phương trình Diophantine, đếm nghiệm trong khoảng): xem trang Thuật toán Euclid mở rộng.

long long ext_gcd(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 = ext_gcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - (a / b) * y1;
    return g;
}

// Phương trình ax ≡ c (mod m) có nghiệm khi gcd(a,m) | c
long long solve_linear(long long a, long long c, long long m) {
    long long x, y;
    long long g = ext_gcd(a, m, x, y);
    if (c % g != 0) return -1;
    long long mod = m / g;
    return (x % mod * (c / g) % mod + mod) % mod;
}

Định lý số dư Trung Hoa (CRT)

Hệ phương trình x≡ri(modmi) với các mi đôi một nguyên tố cùng nhau có nghiệm duy nhất modulo M=∏mi:

pair<long long, long long> crt(long long r1, long long m1, long long r2, long long m2) {
    long long x, y;
    long long g = ext_gcd(m1, m2, x, y);
    long long lcm = m1 / g * m2;
    long long ans = (r1 + m1 * ((r2 - r1) % m2 * x % m2 + m2)) % lcm;
    return {ans, lcm};
}

// Hợp nhiều phương trình:
long long r = 0, m = 1;
for (auto [ri, mi] : equations) {
    auto [new_r, new_m] = crt(r, m, ri, mi);
    r = new_r; m = new_m;
}

Bảng công thức

Độ phức tạp
Kiểm tra nguyên tố O(N)
Sàng nguyên tố đến N O(NloglogN)
GCD O(logmin(a,b))
Extended GCD O(logmin(a,b))
Lũy thừa nhanh ab O(logb)
C(n,k)modp (precompute) O(N) build, O(1) query
CRT (2 phương trình) O(logmin(m1,m2))

Các chủ đề có trang riêng

Trang này là cheatsheet số học nền tảng. Các kỹ thuật dưới đây có trang riêng với trực giác, ví dụ chạy tay, lỗi thường gặp và bài tập (kể cả đề VOI):

Chủ đề Mô tả Trang
Tổ hợp và đếm cơ bản Quy tắc đếm, C(n,k) mod p, chia kẹo, Catalan, modulo hợp số Tổ hợp và đếm cơ bản
Bao hàm loại trừ Đếm phần tử thuộc ít nhất / không thuộc tập nào, derangement, trên bit Nguyên lý bao hàm loại trừ
Hạng hoán vị, dãy thứ k Hạng từ điển, dựng hoán vị/dãy thứ k bằng đếm từng vị trí Hạng của hoán vị và dãy thứ k
Euclid mở rộng Bézout, nghịch đảo modulo bất kỳ, phương trình Diophantine Thuật toán Euclid mở rộng
Đếm số nguyên tố đến N lớn π(N) với N≤1011 bằng thuật toán Lucy, O(N3/4) Đếm số nguyên tố (Lucy/Meissel)
Nguyên lý Dirichlet Chuồng bồ câu, bài dựng nghiệm, dãy modulo tuần hoàn (Pisano) Nguyên lý Dirichlet và tính tuần hoàn
Số lớn Nhận biết tràn long long, __int128, cài số lớn Số lớn và __int128
Hàm nhân tính & Sàng tuyến tính Tính hàm nhân tính (Euler phi, số ước...) cho mọi số đến N trong O(N) Hàm nhân tính
Miller-Rabin & Pollard's Rho Kiểm tra nguyên tố và phân tích thừa số cho N lớn (≤1018) Miller-Rabin & Pollard's Rho
Lucas & modular nâng cao (nk)modp với n rất lớn, CRT, Cipolla Lucas Theorem
Logarithm rời rạc (BSGS) Giải ax≡b(modm) trong O(m) Baby-step Giant-step
Nhân ma trận Tăng tốc truy hồi tuyến tính với N≤1018 Matrix Exponentiation
Berlekamp-Massey Tìm truy hồi tuyến tính ngắn nhất của một dãy Berlekamp-Massey
FFT Nhân hai đa thức / tích chập trong O(NlogN) FFT
Nội suy Lagrange Khôi phục đa thức bậc ≤N−1 qua N điểm Nội suy Lagrange
Burnside & Polya Đếm cấu hình phân biệt dưới nhóm đối xứng Burnside và Polya

Bài tập luyện

Luyện kỹ thuật
  • Lũy thừa modulo (modexp) (Nghiệp dư) Cài đặt lũy thừa nhanh abmodm trong O(logb), khối xây dựng cho mọi bài modulo.
  • Đếm số lượng ước (cntdivs) (Nghiệp dư) Sàng kiểu "duyệt bội" tiền xử lý số ước cho mọi số đến 106, trả lời mỗi truy vấn trong O(1).
  • Hệ số nhị thức (binocoef) (Nghiệp dư) Tiền xử lý giai thừa và nghịch đảo giai thừa (qua Fermat nhỏ) để tính C(a,b)modp trong O(1).
  • Đường thẳng nguyên (lineeq) (Nâng cao) Tìm điểm nguyên trên Ax+By+C=0: phương trình Diophantine giải bằng Euclid mở rộng, chú ý dấu và trường hợp gcd∤C.
  • Trò chơi đồng dư (remgm42) (Nâng cao) Theo CRT, biết xmodci là biết xmodlcm(ci); quy về kiểm tra k∣lcm bằng phân tích thừa số mà không tính lcm (tràn số).
Đề VOI
  • Chìa khóa mã số (voi15_crypt) (Kỳ cựu) VOI 2015: tập đóng dưới gcd/lcm, xét riêng từng số nguyên tố của k và làm việc trên số mũ.
  • Sản xuất gỗ (voi24_wpro) (Kỳ cựu) VOI 2024: quy hoạch động trên các mối nối được giữ lại; số thanh ít nhất phủ độ dài ℓ (nghiệm aL1+bL2=ℓ với a+b nhỏ nhất) tính trong O(1) nhờ nghịch đảo modulo từ Euclid mở rộng.
Trang này có hữu ích không? Đăng nhập để trả lời

Bình luận

Không có bình luận tại thời điểm này.

gnatmake 12.2.0 a68g 3.1.2 nasm 2.16.1 as_x64 2.47 awk 1.3.4 gcc 16.2.0 dotnet 10.0.402 g++ 16.2.0 g++-themis 16.2.0 g++17 16.2.0 g++20 16.2.0 g++23 16.2.0 clang++ 22.1.8 dmd 2.113.0 dart 3.13.6 gforth 0.7.3 gfortran 15.3.0 go 1.27.3 groovyc 5.1.3 javac 26.0.2.1 node 26.12.1 julia 1.13.2 kotlinc 2.4.21 lean 4.35.0 sbcl 2.2.9 lua 5.5.1 nim 2.2.12 fpc 3.2.2 fpc-themis 3.2.2 perl 5.42.3 php 8.5.12 pike 8.0 swipl 9.0.4 pypy3 7.3.23 python3 3.15.1 racket 8.7 ruby 4.0.8 rustc 1.99.1 csc 5.3.0 ctoj-scratch 0.0.1 sed 4.9 swiftc 6.4.1 tclsh 8.6 bun 1.4.4 deno 2.9.8 v 0.5.2 zig 0.17.0