Numere și divizibilitate la atestatul de informatică
Operatorii % și /, extragerea cifrelor, numere prime, divizori, numere perfecte, palindroame și c.m.m.d.c. — cu problemele de atestat în care apar.
Este cel mai des întâlnit grup de subiecte la proba de programare: 12 din cele 40 de probleme din sesiunea Dolj 2026 se rezolvă cu ideile de mai jos. Vestea bună e că aproape toate se sprijină pe două operații și pe trei tipare care se repetă.
Cele două operații de bază
Totul pleacă de aici. Pentru două numere întregi:
| Operație | Ce face | Exemplu |
|---|---|---|
a % b |
restul împărțirii lui a la b |
3815 % 10 → 5 |
a / b |
câtul împărțirii întregi (partea zecimală se pierde) | 3815 / 10 → 381 |
Atenție: în C++, / între două numere int dă împărțire întreagă. 7 / 2 este 3, nu 3.5.
Dacă unul dintre operanzi e real (7 / 2.0), rezultatul devine real — sursa clasică de erori.
Testul de divizibilitate
if (n % d == 0) // d il imparte exact pe n
Aceasta este singura condiție de care ai nevoie pentru divizori, numere prime, numere perfecte și c.m.m.d.c. Dacă restul e zero, împărțirea e exactă.
Extragerea cifrelor
Combinând cele două operații, „desfaci" un număr cifră cu cifră:
n % 10 // ultima cifra
n / 10 // numarul fara ultima cifra
Repetând până când numărul ajunge 0, treci prin toate cifrele, de la dreapta spre stânga:
3815 → cifra 5, ramane 381
381 → cifra 1, ramane 38
38 → cifra 8, ramane 3
3 → cifra 3, ramane 0 ← stop
Aplicat direct la suma cifrelor și la produsul cifrelor.
Numere prime
Un număr este prim dacă are exact doi divizori: 1 și el însuși. 0 și 1 nu sunt prime.
bool estePrim(int n) {
if (n < 2) return false;
for (int d = 2; d * d <= n; d++)
if (n % d == 0) return false;
return true;
}
De ce d * d <= n
Nu e nevoie să cauți divizori până la n, pentru că divizorii vin în perechi. Pentru n = 36:
1 × 36 6 × 6 ← mijlocul, adica radical din 36
2 × 18
3 × 12
4 × 9
Orice divizor mai mare decât √n are deja o pereche mai mică decât √n. Dacă n-ai găsit niciunul
până la √n, nu mai există niciunul nici după. Pentru n = 1.000.000 înseamnă 1000 de pași în loc
de un milion.
Se scrie d * d <= n, nu sqrt(n) — sqrt lucrează cu numere reale și poate da 5.999999 în loc
de 6, ratând ultimul divizor.
Probleme: verificarea unui număr prim · numere prime dintr-un interval · numărarea valorilor prime dintr-un vector · două numere prime cu suma dată
Divizori: numărare și sumă
Aceeași buclă, două rezultate diferite. Diferența stă în limita superioară:
// toti divizorii, inclusiv n
for (int d = 1; d <= n; d++)
if (n % d == 0) c++;
// doar divizorii proprii (fara n insusi)
for (int d = 1; d <= n / 2; d++)
if (n % d == 0) s += d;
Niciun divizor propriu al lui n nu poate depăși n / 2 — de aceea a doua buclă se oprește acolo.
Confuzia între cele două limite e una dintre cele mai frecvente greșeli.
Probleme: numere cu exact 3 divizori
Curiozitate care apare la oral: numerele cu exact 3 divizori sunt întotdeauna pătratele numerelor prime (
4,9,25,49). Orice număr are deja divizorii1și pe el însuși; ca să existe exact încă unul „la mijloc", numărul trebuie să fiep × pcupprim.
Numere perfecte
Un număr este perfect dacă e egal cu suma divizorilor săi proprii. Primele două sunt 6
(1+2+3) și 28 (1+2+4+7+14).
bool estePerfect(int n) {
if (n < 2) return false;
int s = 0;
for (int d = 1; d <= n / 2; d++)
if (n % d == 0) s += d;
return s == n;
}
Probleme: verificarea unui număr perfect · numerele perfecte dintr-un vector
Numere palindrom
Un număr e palindrom dacă rămâne același citit invers: 8, 121, 3003.
bool estePalindrom(int n) {
int inversat = 0, copie = n;
while (copie != 0) {
inversat = inversat * 10 + copie % 10;
copie /= 10;
}
return inversat == n;
}
Linia-cheie se citește: „împinge cifrele deja adunate cu o poziție la stânga, apoi pune ultima
cifră a lui copie pe locul rămas liber."
Se lucrează pe o copie, nu pe n — bucla consumă valoarea, iar la final ai nevoie de n intact
pentru comparație. Este greșeala numărul unu la această categorie.
Probleme: numere palindrom într-un vector
C.m.m.d.c. — algoritmul lui Euclid
int cmmdc(int x, int y) {
if (y == 0) return x;
return cmmdc(y, x % y);
}
Ideea: c.m.m.d.c. al lui x și y este același cu cel al lui y și restul împărțirii lui x la
y. Dacă un număr îi împarte exact și pe x, și pe y, atunci împarte exact și restul.
cmmdc(48, 36) → 48 % 36 = 12 → cmmdc(36, 12)
cmmdc(36, 12) → 36 % 12 = 0 → cmmdc(12, 0)
cmmdc(12, 0) → return 12
Nu contează ordinea argumentelor: cmmdc(36, 48) face un pas în plus și ajunge la același lucru.
Pentru un vector întreg, se aplică în lanț, pentru că operația e asociativă:
d = cmmdc(d, x[i]) la fiecare pas, pornind de la d = x[0].
Probleme: c.m.m.d.c. a două numere · c.m.m.d.c. al elementelor unui vector
Cele trei tipare care se repetă
Dacă reții un singur lucru din pagina asta, reține-l pe acesta. Problemele nu sunt rezolvări diferite, ci aceleași trei structuri combinate.
1. Funcție de test + buclă
Scrii o funcție care răspunde true/false pentru un element, apoi o apelezi pentru fiecare.
Funcționează identic la prime, perfecte, palindroame.
for (int i = 0; i < n; i++)
if (esteCeva(x[i])) { /* ... */ }
2. Flag sau contor pentru cazul gol
Aproape toate enunțurile cer NU EXISTA când nu s-a găsit nimic. Nu poți ști asta decât după
ce ai parcurs tot:
bool gasit = false; // sau: int cate = 0;
for (...)
if (...) { cout << x[i] << " "; gasit = true; }
if (!gasit) cout << "NU EXISTA";
Când enunțul cere câte sunt, contorul înlocuiește flagul — îți dă și răspunsul, și informația „există sau nu".
3. Rezultat parțial acumulat
Pornești de la primul element și îl combini pe rând cu următoarele: d = cmmdc(d, x[i]). Aceeași
structură funcționează la sumă, maxim sau c.m.m.m.c.
Greșeli care se repetă
for (d = 2; d <= n; d++)la verificarea primalității — cânddajunge lan, condiția e adevărată și funcția răspunde „nu e prim" pentru orice număr- Uitarea cazului
n < 2—1apare raportat ca prim d <= nîn loc ded <= n / 2la numere perfecte —nse adaugă la propria sumă- Modificarea lui
nfără copie la palindrom — la finalna devenit0 return 0în cazul de bază la produsul cifrelor — trebuie1, elementul neutru al înmulțirii- Neinițializarea acumulatorilor —
int s;fără= 0pornește de la o valoare oarecare
Toate problemele din această categorie
Fiecare are rezolvare completă în C++, explicată pas cu pas.
- Cel mai mare divizor comun a două numere, folosind o funcție recursivăProgramare
- Produsul cifrelor unui număr, folosind o funcție recursivăProgramare
- Suma cifrelor unui număr, folosind o funcție recursivăProgramare
- Să se afişeze două numere naturale prime a căror sumă este numărul nProgramare
- Să se afişeze numerele perfecte din vectorProgramare
- Să se afişeze numărul elementelor care sunt numere palindromProgramare
- Să se afişeze numărul valorilor prime din vectorProgramare
- Să se afişeze toate numerele mai mici sau egale cu n, care au exact 3 divizoriProgramare
- Să se afişeze toate numerele prime din intervalul închis [a,b]Programare
- Să se calculeze şi să se afişeze cel mai mare divizor comun al elementelor vectoruluiProgramare
- Să se verifice dacă numărul este perfect şi în caz afirmativ să se afişeze mesajul DAProgramare
- Să se verifice dacă numărul este primProgramare