De ce contează?
Vrei să aranjezi 12 scaune în rânduri egale. Poți face 1×12, 2×6 sau 3×4 — perechi de numere care înmulțite dau 12. Exact astea sunt divizorii: numerele care „încap" exact în 12, mereu în perechi.
Ce este un divizor
d este divizor al lui n dacă n se împarte exact la d, adică n % d == 0.
Divizorii lui 12 sunt: 1, 2, 3, 4, 6, 12.
Varianta simplă: O(n)
Verificăm fiecare candidat de la 1 la n:
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
for (int d = 1; d <= n; d++) {
if (n % d == 0) {
cout << d << " "; // 12 -> 1 2 3 4 6 12
}
}
return 0;
}Corect, dar pentru n mare (un miliard) face un miliard de pași — prea lent.
Ideea cheie: divizorii vin în perechi
Dacă d divide n, atunci și n / d divide n. Cei doi sunt o pereche așezată
simetric față de √n:
1 | 2 | 3 | 4 | 6 | 12 |
Deci e suficient să cauți d doar până la √n: pentru fiecare d găsit, ai gratis și
perechea n / d.
Varianta rapidă: O(√n)
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int cate = 0;
for (int d = 1; (long long)d * d <= n; d++) { // d pana la radical din n
if (n % d == 0) {
cate++; // divizorul d
if (d != n / d) { // evitam dublarea la patrat perfect
cate++; // perechea n/d
}
}
}
cout << "Numar de divizori: " << cate << "\n"; // 12 -> 6
return 0;
}Condiția d * d <= n e echivalentă cu d <= √n, dar evită calculul cu sqrt (care
lucrează cu numere reale și poate da erori de rotunjire). Scrie (long long)d * d ca
să nu se spargă produsul la n mare.
De ce verificarea d != n / d
La un pătrat perfect (ex. 36), când d = 6 avem n / d = 6 — aceeași valoare.
Fără verificarea d != n / d, l-ai număra de două ori. Pentru orice alt divizor,
perechea e diferită și o adaugi normal.
Complexitate
| Variantă | Timp | Spațiu |
|---|---|---|
| naivă (1..n) | O(n) | O(1) |
| cu perechi (1..√n) | O(√n) | O(1) |
Pentru n = 10⁹: varianta naivă face ~10⁹ pași (prea lent), cea cu perechi doar ~31.000.
Capcane reale la divizori:
- Bucla până la
n: corectă, dar O(n) — depășește timpul pentrunmare. Mergi până la √n. - Overflow în condiție:
d * dînintse sparge pentrudpeste ~46.000. Scrie(long long)d * d <= n. - Dubla numărare la pătrate perfecte: uiți
d != n / dși 36 iese cu un divizor în plus. sqrtîn condiție:d <= sqrt(n)poate rata sau adăuga un divizor din cauza rotunjirii. Preferăd * d <= n.
De reținut
ddivizor al luin⟺n % d == 0.- Divizorii vin în perechi
(d, n/d)→ cauți doar până la √n, cost O(√n). - La pătrate perfecte, perechea coincide — nu număra divizorul de două ori.