Ciurul lui Eratostene este o metodă rapidă prin care stabilește despre fiecare număr natural mai mic sau egal cu un n dat dat este prim sau nu. Valoarea lui n trebuie să fie suficient de mică pentru a putea declara un tablou P cu n+1 elemente, un element P[k] având valoarea 1 dacă k este prim, respectiv valoarea 0 dacă k nu este prim.
Următoarea secvență C++ construiește tabloul P[]:
int P[n+1];
for(int i = 0 ; i <= n ; i ++)
P[i] = 1;
P[0] = P[1] = 0;
for(int i = 2 ; i * i <= n ; i ++)
if(P[i] == 1)
for(int j = 2 ; i * j <= n ; j ++)
P[i * j] = 0;
Ideea de mai sus poate fi utilizată pentru a determina diverse rezultate în care intervin divizorii unui număr, rezultate calculate pentru toate numerele mai mici sau egale cu n:
- numărul de divizori
- suma divizorilor
- cel mai mic divizor prim
- cel mai mare divizor prim
- indicatorul lui Euler
Numărul de divizori
- construim un vector
Nr[]. La final,Nr[x]va fi numărul de divizori ai luix; - inițializăm elementele vectorului
Nr[]cu0; - parcurgem vectorul și pentru fiecare element
Nr[i]mărim valorile elementelorNr[k], undek = i * jeste multiplu al luii– dacăieste divizor al luik, atunci trebuie numărat ca atare.
int Nr[DIM + 1];
for(int i = 1 ; i <= DIM ; i ++)
Nr[i] = 0;
for(int i = 1; i <= DIM ; i ++)
for(int j = 1 ; i * j <= DIM ; j ++)
Nr[i * j] ++;
OBS: Un număr x este prim dacă și numai dacă la final Nr[x] este egal cu 2.
Suma divizorilor
- construim un vector
S[]. La final,S[x]va reprezenta suma divizorilor luix; - inițializăm elementele vectorului
S[]cu0; - parcurgem vectorul și pentru fiecare element
S[i]mărim valorile elementelorS[k]cui, undek = i * jeste multiplu al luii– dacăieste divizor al luik, atunci trebuie adunat la suma divizorilor luik.
int S[DIM + 1];
for(int i = 1 ; i <= DIM ; i ++)
S[i] = 0;
for(int i = 1; i <= DIM ; i ++)
for(int j = 1 ; i * j <= DIM ; j ++)
S[i * j] += i;
OBS: Un număr x este prim dacă și numai dacă la final S[x] este egal cu x+1.
Cel mai mic/mare divizor prim
- construim un vector
M[]. La final,M[x]va reprezenta cel mai mic divizor (factor) prim al luix; - inițializăm elementele vectorului
M[x]cux– pentru numerele prime cel mai mic factor prim sunt ele însele; - parcurgem numerele începând de la
2și pentru fiecare număriprim (pentru careM[i] = i) modificăm, dacă este cazul, cel mai mic factor prim pentru toți multiplik = i * jluii.
int M[DIM + 1];
for(int i = 1 ; i <= DIM ; i ++)
M[i] = i;
for(int i = 2; i <= DIM ; i ++)
if(M[i] == i)
for(int j = 2 ; i * j <= DIM ; j ++)
if(M[i * j] == i * j)
M[i * j] = i;
OBS:
- Un număr
xeste prim dacă și numai dacă la finalM[x]este egal cux. - La parcurgerea multiplilor lui
i, vom modifica multiplulk = i * jnumai dacăM[k]este încăk. De exemplu, pentrui=3, nu-l mai modifică peM[6]– a fost deja modificat pentrui=2. - Dacă modificăm
M[k]de pentru fiecarei, deoareceieste considerat în ordine crescătoare, la finalM[k]va memora cel mai mare divizor prim al luik. Următoarea secvență obține acest rezultat – observați că modificările sunt minore:
int M[DIM + 1];
for(int i = 1 ; i <= DIM ; i ++)
M[i] = i;
for(int i = 2; i <= DIM ; i ++)
if(M[i] == i)
for(int j = 2 ; i * j <= DIM ; j ++)
M[i * j] = i;
Indicatorul lui Euler
Indicatorul lui Euler este tratat în acest articol. Reluăm aici numai secvența C/C++:
int F[DIM + 1];
for(int i =1 ; i <= DIM ; i ++)
F[i] = i;
for(int i = 2; i <= DIM ; i ++)
if(F[i] == i)
{
for(int j = 1 ; j * i <= DIM ; j ++)
F[j * i]= F[j * i] / i * (i - 1);
}
OBS: Un număr x este prim dacă și numai dacă la final F[x] este egal cu x-1.
Alte probleme
Încercați să determinați în același mod:
- numărul factorilor primi
- suma/produsul factorilor primi
- etc.
Probleme ataşate
| Nr. | Problema | Clasa | Dificultate | Operații I/O |
|---|---|---|---|---|
| 1 | #3313 - Eratostene2 | 9 | medie | fișiere |
| 2 | #3314 - Eratostene3 | 9 | medie | fișiere |
