De ce contează?
Vrei să împarți un tort în trei felii egale, dar tortul există doar „pe un ceas”
care se resetează la fiecare m ore. Nu poți tăia ceasul în trei. În schimb poți
face ceva ciudat dar corect: în loc să împarți la 3, înmulțești cu „opusul lui 3”
— numărul care, înmulțit cu 3, te readuce fix la 1. Acel opus se numește invers
modular, și e singura cale să împarți când lucrezi modulo.
De ce ai nevoie de invers
În lecția anterioară ai văzut că adunarea și înmulțirea se distribuie frumos peste
modulo: poți reduce la fiecare pas și rezultatul rămâne corect. Împărțirea NU se
poartă la fel. Concret, (a / b) % m nu este egal cu (a % m) / (b % m) — uneori
b nici nu divide pe a în întregi, deci a / b nici nu are sens ca număr întreg.
Soluția e să înlocuiești împărțirea cu o înmulțire. Definim inversul modular al
lui b modulo m ca numărul b^(-1) pentru care:
b · b^(-1) ≡ 1 (mod m)
Cu el, împărțirea devine înmulțire:
a / b ≡ a · b^(-1) (mod m)
Inversul joacă exact rolul lui 1 / b din aritmetica obișnuită: înmulțirea cu el
„anulează” înmulțirea cu b. Atenție: inversul există doar dacă gcd(b, m) = 1
(adică b și m sunt prime între ele). Din fericire, când m e prim, orice b
care nu e multiplu de m are invers.
Exemplu pas cu pas: inversul lui 3 modulo 7
Căutăm numărul x cu 3 · x ≡ 1 (mod 7). Încercăm pe rând:
3 · 1 = 3, iar3 % 7 = 3— nu e 13 · 2 = 6, iar6 % 7 = 6— nu e 13 · 3 = 9, iar9 % 7 = 2— nu e 13 · 4 = 12, iar12 % 7 = 5— nu e 13 · 5 = 15, iar15 % 7 = 1— am găsit,x = 5
Deci inversul lui 3 modulo 7 este 5. Verificare a împărțirii: 6 / 3 ar trebui
să dea 2; cu invers, 6 · 5 = 30, iar 30 % 7 = 2. Corect.
Căutarea prin încercări e O(m) — prea lentă pentru m = 1000000007. Aici intervine
mica teoremă a lui Fermat: dacă m e prim și b nu e multiplu de m, atunci
b^(m-1) ≡ 1 (mod m). Împărțind, obținem formula de aur:
b^(-1) ≡ b^(m-2) (mod m)
Calculul lui b^(m-2) pare uriaș, dar cu exponentiere rapidă (ridicare la putere
prin pătrate) îl faci în O(log m) pași — câteva zeci de înmulțiri.
Implementare C++
#include <iostream>
using namespace std;
const long long MOD = 1000000007; // modul prim
// ridicare la putere modulo, in timp logaritmic O(log e)
long long putereMod(long long b, long long e, long long m) {
long long rez = 1;
b %= m; // reducem baza de la inceput
while (e > 0) {
if (e & 1) { // daca bitul curent e 1
rez = (rez * b) % m; // long long ca sa nu dea overflow
}
b = (b * b) % m; // ridicam baza la patrat
e >>= 1; // trecem la bitul urmator
}
return rez;
}
// inversul modular prin Fermat: b^(m-2) mod m (cere m prim)
long long invers(long long b, long long m) {
return putereMod(b, m - 2, m);
}
int main() {
cout << invers(3, 7) << "\n"; // 5 -> invers(3,7)=5
// impartire modulo: a / b = a * invers(b)
long long a = 6, b = 3;
long long rez = (a % MOD) * invers(b, MOD) % MOD;
cout << rez << "\n"; // 2 -> 6 / 3 = 2
return 0;
}Observă cum nu apare niciodată operatorul / aplicat modulo: împărțirea „la 3” s-a
transformat în înmulțirea cu invers(3).
Complexitate
| Operație | Timp | De ce |
|---|---|---|
putereMod(b, e, m) | O(log e) | înjumătățim exponentul la fiecare pas |
invers(b, m) prin Fermat | O(log m) | un singur apel cu exponentul m - 2 |
| căutare invers prin încercări | O(m) | testezi pe rând fiecare candidat — prea lent |
Inversul modular există doar dacă gcd(b, m) = 1. Când m e prim, această
condiție e îndeplinită de orice b care nu e multiplu de m, deci formula lui
Fermat b^(m-2) merge mereu. Dacă m NU e prim, Fermat nu se aplică — atunci ai
nevoie de algoritmul lui Euclid extins.
- Folosești
/direct modulo: scrii(a / b) % MODși obții un rezultat fals. Împărțirea nu se distribuie peste modulo — înmulțește cuinvers(b, MOD). - Aplici Fermat când
mnu e prim: formulab^(m-2)dă inversul DOAR pentrumprim. Pe un modul compus rezultatul e greșit; folosește Euclid extins. - Overflow în exponentiere fără
long long:rez * bpoate depăși unintcu mult înainte de modulo. Ține totul pelong longși reduci% mimediat. - Ceri inversul lui
b = 0: zero nu are invers modular (nu existăxcu0 · x ≡ 1). Tratează separat acest caz, nu apelainvers(0, MOD).
| 3·x | 3 | 6 | 9 | 12 | 15 |
| x | 1 | 2 | 3 | 4 | 5 |
Recapitulare
- Împărțirea nu se distribuie peste modulo; împarți înmulțind cu inversul:
a / b ≡ a · b^(-1). - Inversul există doar când
gcd(b, m) = 1; pentrumprim, Fermat dăb^(-1) ≡ b^(m-2). - Calculezi inversul cu exponentiere rapidă pe
long long, în O(log m), reducând% mla fiecare pas.