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 * j
este multiplu al luii
– dacăi
este 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 * j
este multiplu al luii
– dacăi
este 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ări
prim (pentru careM[i] = i
) modificăm, dacă este cazul, cel mai mic factor prim pentru toți multiplik = i * j
luii
.
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
x
este prim dacă și numai dacă la finalM[x]
este egal cux
. - La parcurgerea multiplilor lui
i
, vom modifica multiplulk = i * j
numai 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
, deoarecei
este 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 |