Các phép cộng, trừ, nhân

Đối với phép cộng ta có:

(a+b)modm=(amodm+bmodm)modm
Tương tự với phép trừ và nhân:
(ab)modm=(amodmbmodm)modm

(ab)modm=((amodm)(bmodm))modm

Lưu ý: Vì kết quả có thể âm nhưng hầu như ta đều muốn kết quả của phép mod là dương nên ta sẽ cộng thêm m vào cuối:

(a+b)modm=((amodm+bmodm)modm+m)modm
(ab)modm=((amodmbmodm)modm+m)modm

(ab)modm=(((amodm)(bmodm))modm+m)modm


Tính
abmodm

Ta cũng có thể dùng lũy thừa nhị phân kết hợp thêm

modm:

long long binpow(long long a, long long b, long long m) {
    long long res = 1;
    a %= m;
    while(b > 0) {
        if(b & 1)
            res = res * a % m;
        a = a * a % m;
        b >>= 1;
    }
    return res;
}

Phép chia

mod trong phép chia không giống với cộng, trừ, hay nhân, mà ta sẽ dùng tới một khái niệm mới: nghịch đảo modular.

Nghịch đảo modular của một số

a là một số
x
sao cho
ax1(modm)

x
cũng được gọi là
a1
.

Lưu ý: Ta chỉ có thể tìm được nghịch đảo modular của

a khi
a
m
là 2 số nguyên tố cùng nhau
(gcd(a,m)=1)
.

Tìm nghịch đảo modular bằng Euclid mở rộng

Ta có:

gcd(a,m)=1ax+my=1
mod m cho cả 2 vế (dùng công thức cộng mod bên trên
my
sẽ mất vì
mymodm=0
)
ax1(modm)

int x, y, g;
g = extended_euclidean(a, m, x, y);
if(g == 1) {
    x = (x % m + m) % m;
    cout << x;
}
else
    cout << "No solution";

Tìm nghịch đảo modular bằng lũy thừa nhị phân

Theo định lý Euler, nếu

a
m
là hai số nguyên tố cùng nhau thì:
aϕ(m)1(modm)
với
ϕ
phi hàm Euler.
Nếu
m
là số nguyên tố thì quy về định lý nhỏ Fermat:
am11(modm)
(với
m
nguyên tố thì
ϕ(m)=m1
).
Nhân cả hai vế cho
a1
ta được:
a1{am2với m nguyên tốaϕ(m)1với m không nguyên tố(modm)

Từ đó ta có thể dùng lũy thừa nhị phân như trên để tính.

Tìm nghịch đảo modular cho
m
số (chỉ áp dụng cho
m
nguyên tố)

Ta sẽ xây dựng một mảng

inv để lưu lại nghịch đảo modular của các số tới
m
.
Nếu ta duyệt i từ
1
tới
m
, sau đó tính nghịch đảo modular của từng i, độ phức tạp sẽ là
O(mlogm)
.
Tuy nhiên có một cách để tính trong
O(m)
:
Với số nguyên tố
m
>
a
, theo Euclidean divison, tồn tại 2 số
q
p
sao cho:
m=aq+p
với
q=ma
p=mmoda

m=aq+p

aq+p0(modm)

apq(modm)

a1qp(modm)

a1qp1(modm)

Có thể thấy
qp1
là số âm nên ta sẽ cộng thêm
m
vào:
a1mqp1(modm)

Thay
q
p
như bên trên:
a1mma(mmoda)1(modm)

Hay:
inv[a]mmainv[mmoda](modm)

mmoda<a
nên ta sẽ tính được
inv[a]
dựa vào các giá trị trước.

inv[0] = inv[1] = 1;
for(int i = 2; i <= MAXN; ++i) // MAXN <= mod
    inv[i] = mod - (long long)(mod / i) * inv[mod % i] % mod;