Algoritmul pentru a calcula numărul de divizori ai unui număr dat

voturi
163

Care ar fi algoritmul cel mai optim (performanță-înțelept), pentru a calcula numărul de divizori ai unui număr dat?

Va fi grozav dacă ai putea oferi pseudocod sau un link către un exemplu.

EDIT: Toate răspunsurile au fost foarte utile, vă mulțumesc. Sunt punerea în aplicare a ciurul lui Atkin și apoi voi folosi ceva similar cu ceea ce a indicat Jonathan Leffler. Link-ul postat de Justin Bozonier are informații suplimentare cu privire la ceea ce am vrut.

Întrebat 21/09/2008 la 06:44
sursa de către utilizator
În alte limbi...                            


28 răspunsuri

voturi
1

Vrei ciurul Atkin, descris aici: http://en.wikipedia.org/wiki/Sieve_of_Atkin

Publicat 21/09/2008 la 06:53
sursa de către utilizator

voturi
0

Nu este aceasta doar o chestiune de factoring numărul - determinarea tuturor factorilor de numărul? Puteți decide apoi dacă aveți nevoie de toate combinațiile de unul sau mai mulți factori.

Deci, un algoritm posibil ar fi:

factor(N)
    divisor = first_prime
    list_of_factors = { 1 }
    while (N > 1)
        while (N % divisor == 0)
            add divisor to list_of_factors
            N /= divisor
        divisor = next_prime
    return list_of_factors

Este apoi până la tine pentru a combina factorii pentru a determina restul răspunsului.

Publicat 21/09/2008 la 06:59
sursa de către utilizator

voturi
74

Dmitriy este corect că veți dori ciurul Atkin pentru a genera lista de prim, dar nu cred că are grijă de întreaga problemă. Acum, că aveți o listă de numere prime, va trebui să vedeți cât de multe dintre aceste numere prime acționează ca un divizor (și cât de des).

Iată câteva piton pentru algo Uita - te aici și căutați „Subiect: matematica - nevoie divizori algoritm“. Doar contoriza numărul de elemente din listălocle retrocedezetoate acestea.

Iată un Dr. Math care explica ce face mai exact ce trebuie să faci matematic.

În esență , se reduce la cazul în care numărul dvs. neste:
n = a^x * b^y * c^z
( în cazul în care a, b, și c sunt n lui divizori prime si x, y, și z reprezintă numărul de ori pe care împărțitor se repetă) , atunci numărul total pentru toate divizorii este:
(x + 1) * (y + 1) * (z + 1).

Editare: BTW, pentru a găsi o, b, c, etc veți dori să facă ceea ce echivalează cu o algo lacom dacă am înțelege corect acest lucru. Începeți cu dvs. cel mai mare prim împărțitor și înmulțiți-l de la sine până la o multiplicare suplimentară ar depăși numărul n. Apoi se trece la următorul cel mai mic factor și ori anterior prim ^ numărul de ori a fost înmulțit cu prim curent și să păstreze înmulțirea de prim până la următoarea va depăși n ... etc Țineți evidența numărului de ori înmulțiți divizori împreună și să aplice aceste numere în formula de mai sus.

Nu sunt 100% sigur mea descriere Algo, dar în cazul în care nu este că e ceva similar.

Publicat 21/09/2008 la 07:03
sursa de către utilizator

voturi
-1

Nu știu cea mai eficientă metodă, dar aș face următoarele:

  • Crearea unui tabel de amorse pentru a găsi toate amorsează mai mică sau egală cu rădăcina pătrată a numărului (Personal, mi-ar folosi ciurul lui Atkin)
  • Contorizați toate amorsează mai mică sau egală cu rădăcina pătrată a numărului și înmulțiți cu doi. Dacă rădăcina pătrată a numărului este un număr întreg, apoi scade una din variabila count.

Ar trebui să funcționeze \ o /

Dacă aveți nevoie, eu pot codul ceva până mâine în C pentru a demonstra.

Publicat 21/09/2008 la 07:16
sursa de către utilizator

voturi
5

Ciurul Atkin este o versiune optimizată a sitei de Eratostene care oferă toate numerele prime până la un anumit număr întreg. Ar trebui să fie în măsură să Google acest lucru pentru mai multe detalii.

Odată ce aveți această listă, este o chestiune simplă de a împărți numărul dvs. de fiecare prim pentru a vedea dacă este un divizor exact (de exemplu, restul este zero).

Pașii de bază de calcul divizorii pentru un număr (n) sunt [acest lucru este pseudocod convertit de la codul de real, așa că sper că nu am introdus erori]:

for z in 1..n:
    prime[z] = false
prime[2] = true;
prime[3] = true;

for x in 1..sqrt(n):
    xx = x * x

    for y in 1..sqrt(n):
        yy = y * y

        z = 4*xx+yy
        if (z <= n) and ((z mod 12 == 1) or (z mod 12 == 5)):
            prime[z] = not prime[z]

        z = z-xx
        if (z <= n) and (z mod 12 == 7):
            prime[z] = not prime[z]

        z = z-yy-yy
        if (z <= n) and (x > y) and (z mod 12 == 11):
            prime[z] = not prime[z]

for z in 5..sqrt(n):
    if prime[z]:
        zz = z*z
        x = zz
        while x <= limit:
            prime[x] = false
            x = x + zz

for z in 2,3,5..n:
    if prime[z]:
        if n modulo z == 0 then print z
Publicat 21/09/2008 la 07:36
sursa de către utilizator

voturi
46

Există o mulțime mai multe tehnici de factoring decât sita Atkin. De exemplu , să presupunem că vrem să factor 5893. Ei bine sqrt sa este 76.76 ... Acum vom încerca să scrie 5893 ca un produs de pătrate. Pai (77 * 77 - 5893) = 36 , care este de 6 la pătrat, deci 5893 = 77 * 77 - * 6 = 6 (77 + 6) (77-6) = 83 * 71. În cazul în care nu a funcționat ne - am fi analizat dacă 78 * 78-5893 a fost un pătrat perfect. Si asa mai departe. Cu această tehnică puteți testa rapid pentru factorii de lângă rădăcina pătrată a n mult mai rapid decât prin testarea amorse individuale. Dacă combina aceasta tehnica pentru a exclude amorse mari , cu o sită, veți avea o metodă de factoring mult mai bine decât doar cu sita.

Și acesta este doar unul dintr-un număr mare de tehnici care au fost dezvoltate. Acesta este unul destul de simplu. Te-ar lua o lungă perioadă de timp pentru a învăța, să zicem, teoria numerelor suficient pentru a înțelege tehnicile de factoring bazate pe curbe eliptice. (Știu că există. Eu nu le înțeleg.)

Prin urmare , dacă nu se face cu numere întregi mici, nu aș încerca să rezolve această problemă eu. În schimb aș încerca să găsească o modalitate de a folosi ceva de genul PARI biblioteca , care are deja o soluție extrem de eficientă pusă în aplicare. Cu că pot factor un număr aleatoriu de 40 cifre ca 124321342332143213122323434312213424231341 în aproximativ 0.05 secunde. (Factorizarea sa, în cazul în care ați întrebat, este de 29 * 439 * 1321 * 157907 * 284749 * 33843676813 * 4857795469949. Sunt destul de încrezător că nu a figura asta folosind sita de Atkin ...)

Publicat 21/09/2008 la 09:47
sursa de către utilizator

voturi
9

Un răspuns la întrebarea dvs. depinde în mare măsură de mărimea întreg. Metode pentru un număr mic, de exemplu, mai puțin de 100 de biți și pentru numerele de ~ 1000 biți (cum ar fi utilizat în criptografie) sunt complet diferite.

Publicat 21/09/2008 la 19:38
sursa de către utilizator

voturi
27

Nu sunt de acord că sita Atkin este calea de a merge, deoarece ar putea lua cu ușurință mai mult pentru a verifica fiecare număr în [1, n] pentru primality decât ar fi de a reduce numărul de diviziuni.

Iată un exemplu de cod care, deși ușor hackier, în general, este mult mai rapid:

import operator
# A slightly efficient superset of primes.
def PrimesPlus():
  yield 2
  yield 3
  i = 5
  while True:
    yield i
    if i % 6 == 1:
      i += 2
    i += 2
# Returns a dict d with n = product p ^ d[p]
def GetPrimeDecomp(n):
  d = {}
  primes = PrimesPlus()
  for p in primes:
    while n % p == 0:
      n /= p
      d[p] = d.setdefault(p, 0) + 1
    if n == 1:
      return d
def NumberOfDivisors(n):
  d = GetPrimeDecomp(n)
  powers_plus = map(lambda x: x+1, d.values())
  return reduce(operator.mul, powers_plus, 1)

PS Asta e de lucru cod Python pentru a rezolva această problemă.

Publicat 23/09/2008 la 02:53
sursa de către utilizator

voturi
10

Această întrebare interesantă este mult mai greu decât pare, și nu a primit un răspuns. Problema poate fi luat în 2 întrebări foarte diferite.

1 dat N, găsiți lista L de prim factori N lui

2 L dată, se calculează numărul de combinații unice

Toate răspunsurile pe care le văd până acum se referă la # 1 și nu reușesc să menționeze că nu este maleabil pentru un număr enorm. Pentru moderat de dimensiuni N, chiar și numere pe 64 de biți, este ușor; pentru enorm N, problema factoring poate lua „pentru totdeauna“. criptare cu cheie publica depinde de acest lucru.

Întrebarea # 2 are nevoie de mai multe discuții. Dacă L conține doar numere unice, acesta este un calcul simplu, folosind formula de combinație pentru a alege obiecte k din n elemente. De fapt, trebuie să însumați rezultatele din aplicarea formulei în timp ce variază k de la 1 la sizeof (L). Cu toate acestea, L va conține, de obicei, mai multe apariții ale mai multor amorse. De exemplu, L = {2,2,2,3,3,5} este factorizarea N = 360. Acum, această problemă este destul de dificil!

Retratarea # 2, având în vedere colecția C care conține elemente k, astfel încât elementul A are un „duplicate, iar elementul b are b“ duplicate, etc. numărul de combinații unice de la 1 la k-1 elemente sunt acolo? De exemplu, {2}, {2,2}, {2,2,2}, {2,3}, {2,2,3,3} trebuie de fiecare dată să apară și numai o singură dată, dacă L = {2,2 , 2,3,3,5}. Fiecare astfel de sub-colecție unică este un divizor unic de N prin înmulțirea elementelor din subcolecțiilor.

Publicat 04/11/2008 la 03:52
sursa de către utilizator

voturi
5

S-ar putea încerca asta. Este un pic hackish, dar este destul de rapid.

def factors(n):
    for x in xrange(2,n):
        if n%x == 0:
            return (x,) + factors(n/x)
    return (n,1)
Publicat 18/07/2009 la 04:31
sursa de către utilizator

voturi
3

Înainte de a vă angaja într-o soluție considera că abordarea Sieve s-ar putea să nu fie un răspuns bun în cazul tipic.

Un timp în urmă a existat o întrebare prim și am făcut un test de timp - pentru numere întregi pe 32 de biți, cel puțin a determina dacă acesta a fost prim-a fost mai lent decât forța brută. Există doi factori întâmplă:

1) În timp ce un om ia un timp pentru a face o diviziune acestea sunt foarte rapide pe computer - similar cu costul de a căuta răspunsul.

2) Dacă nu aveți o masă de prim puteți face o buclă care se execută în întregime în memoria cache L1. Acest lucru face mai rapid.

Publicat 18/07/2009 la 05:11
sursa de către utilizator

voturi
5

Odată ce ai prim factorizarea, există o modalitate de a găsi numărul de divizori. Adăugați unul la fiecare dintre exponenții pe fiecare factor individual și apoi se multiplica exponenții împreună.

De exemplu: 36 Prime Factorizarea: 2 ^ 2 * 3 ^ 2 divizori: 1, 2, 3, 4, 6, 9, 12, 18, 36 Numărul de divizori: 9

Adăugați unul la fiecare exponent 2 ^ 3 * 3 ^ 3 exponenți Înmulțiți: 3 * 3 = 9

Publicat 02/02/2010 la 01:28
sursa de către utilizator

voturi
2

Divizori face ceva spectaculos: ei împart complet. Dacă doriți să verificați numărul de divizori pentru un număr, n, este în mod clar este redundantă ca să depășească întregul spectru, 1...n. Eu nu am făcut nici o cercetare în profunzime pentru acest lucru , dar am rezolvat problema proiectului lui Euler 12 pe numere triunghiulara . Soluția mea pentru o mai mare de 500 de divizori testul a fugit pentru 309504 microsecunde (~ 0.3s). Am scris această funcție pentru soluția divizor.

int divisors (int x) {
    int limit = x;
    int numberOfDivisors = 1;

    for (int i(0); i < limit; ++i) {
        if (x % i == 0) {
            limit = x / i;
            numberOfDivisors++;
        }
    }

    return numberOfDivisors * 2;
}

Pentru fiecare algoritm, există un punct slab. Am crezut că acest lucru a fost slab împotriva numere prime. Dar, din moment ce numerele triunghiulare nu sunt de imprimare, acesta a servit scopul său impecabil. Din profilare mea, cred că a făcut-o destul de bine.

Sărbători fericite.

Publicat 30/12/2010 la 22:19
sursa de către utilizator

voturi
33

@Yasky

Funcția dvs. divizori are un bug în care acesta nu funcționează corect pentru pătrate perfecte.

Încerca:

int divisors(int x) {
    int limit = x;
    int numberOfDivisors = 0;

    if (x == 1) return 1;

    for (int i = 1; i < limit; ++i) {
        if (x % i == 0) {
            limit = x / i;
            if (limit != i) {
                numberOfDivisors++;
            }
            numberOfDivisors++;
        }
    }

    return numberOfDivisors;
}
Publicat 23/03/2011 la 15:32
sursa de către utilizator

voturi
6

Doar o linie
m - am gândit foarte despre întrebarea ta cu grija și am încercat să scriu o piesă extrem de eficiente și performant de cod pentru a imprima toate divizorii unui număr dat pe ecran avem nevoie doar de o singură linie de cod! (opțiune utilizare -std = c99 în timp ce compilare prin gcc)

for(int i=1,n=9;((!(n%i)) && printf("%d is a divisor of %d\n",i,n)) || i<=(n/2);i++);//n is your number

pentru a găsi un număr de divizori puteți utiliza următoarea funcție foarte foarte rapid (de lucru corect pentru toate număr întreg, cu excepția 1 și 2)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    return counter;
}

sau dacă vă trateze număr dat ca un divizor (de lucru corect pentru toate număr întreg, cu excepția 1 și 2)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    return ++counter;
}

NOTĂ: două funcții de mai sus funcționează corect pentru toate numărul întreg pozitiv, cu excepția numărul 1 și 2, deci este funcțional pentru toate numerele care sunt mai mari decât 2, dar dacă aveți nevoie pentru a acoperi 1 și 2, puteți utiliza una dintre următoarele funcții (un pic Mai lent)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    if (n==2 || n==1)
    {
    return counter;
    }
    return ++counter;
}

SAU

int number_of_divisors(int n)
{
    int counter,i;
for(counter=0,i=1;(!(i==n) && !(n%i) && (counter++)) || i<=(n/2);i++);
    return ++counter;
}

mici este frumos :)

Publicat 11/11/2011 la 03:59
sursa de către utilizator

voturi
1

metoda număr prim este foarte clar aici. P [] este o listă de prim număr mai mic sau egal sq = sqrt (n);

for (int i = 0 ; i < size && P[i]<=sq ; i++){
          nd = 1;
          while(n%P[i]==0){
               n/=P[i];
               nd++;
               }
          count*=nd;
          if (n==1)break;
          }
      if (n!=1)count*=2;//the confusing line :D :P .

     i will lift the understanding for the reader  .
     i now look forward to a method more optimized  .
Publicat 10/01/2013 la 00:12
sursa de către utilizator

voturi
8

Aici este un drept înainte O (sqrt (n)) algoritmul. Am folosit acest lucru pentru a rezolva euler proiect

def divisors(n):
    count=2 # accounts for 'n' and '1'
    i=2
    while(i**2 < n):
        if(n%i==0):
            count+=2
        i+=1
    count+=(1 if i**2==n else 0)
    return count  
Publicat 05/04/2013 la 05:32
sursa de către utilizator

voturi
1

manuale teoria numerelor apela funcția tau de împărțitor-numărare. Primul fapt interesant este că este multiplicativă, adică. τ (ab) = τ (a) τ (b), atunci când a și b nu au nici un factor comun. (Proof: fiecare pereche de divizori a și b dă un divizor distinct de ab).

Acum, rețineți că pentru prim-pa, τ (p ** k) = k + 1 (puterile p). Astfel, puteți calcula cu ușurință τ (n) de la factorizarea său.

Cu toate acestea factorizari un număr mare poate fi lent (securitatea RSA crytopraphy depinde de produsul a două numere prime mari, fiind greu de factoriza). Acest lucru sugerează că acest algoritm optimizat

  1. Testați dacă numărul este prim (rapid)
  2. Dacă da, reveniți 2
  3. În caz contrar, factoriza numărul (lent , dacă mai multe mari factori prime)
  4. Calculeaza τ (n) din factorizarea
Publicat 14/07/2013 la 13:15
sursa de către utilizator

voturi
1

Ceea ce urmează este un program C pentru a găsi numărul divizorilor unui număr dat.

Complexitatea algoritmului de mai sus este O (sqrt (n)).

Acest algoritm va funcționa corect pentru numărul care sunt pătrate perfecte precum și numerele care nu sunt pătrate perfecte.

Rețineți că UPPERLIMIT buclei este setat la rădăcina pătrată a numărului de a avea algoritmul cel mai eficient.

Rețineți că stocarea UPPERLIMIT într-o variabilă separată economisește, de asemenea, timpul, nu ar trebui să apelați funcția sqrt în secțiunea condiție a pentru bucla, acest lucru economisește, de asemenea, timpul de calcul.

#include<stdio.h>
#include<math.h>
int main()
{
    int i,n,limit,numberOfDivisors=1;
    printf("Enter the number : ");
    scanf("%d",&n);
    limit=(int)sqrt((double)n);
    for(i=2;i<=limit;i++)
        if(n%i==0)
        {
            if(i!=n/i)
                numberOfDivisors+=2;
            else
                numberOfDivisors++;
        }
    printf("%d\n",numberOfDivisors);
    return 0;
}

În loc de cele de mai sus pentru bucla puteți utiliza, de asemenea, următoarea buclă, care este chiar mai eficient deoarece acest lucru elimină necesitatea de a găsi pătrat-rădăcină a numărului.

for(i=2;i*i<=n;i++)
{
    ...
}
Publicat 19/08/2014 la 14:35
sursa de către utilizator

voturi
1

Aici este o funcție pe care am scris. este cel mai rau complexitate este timpul (sqrt (n)), cel mai bun timp pe de altă parte, O este O (log (n)). Acesta vă oferă toate divizorii prime, împreună cu numărul de apariție sale.

public static List<Integer> divisors(n) {   
    ArrayList<Integer> aList = new ArrayList();
    int top_count = (int) Math.round(Math.sqrt(n));
    int new_n = n;

    for (int i = 2; i <= top_count; i++) {
        if (new_n == (new_n / i) * i) {
            aList.add(i);
            new_n = new_n / i;
            top_count = (int) Math.round(Math.sqrt(new_n));
            i = 1;
        }
    }
    aList.add(new_n);
    return aList;
}
Publicat 01/12/2014 la 13:02
sursa de către utilizator

voturi
3

Aceasta este o soluție eficientă:

#include <iostream>
int main() {
  int num = 20; 
  int numberOfDivisors = 1;

  for (int i = 2; i <= num; i++)
  {
    int exponent = 0;
    while (num % i == 0) {
        exponent++; 
        num /= i;
    }   
    numberOfDivisors *= (exponent+1);
  }

  std::cout << numberOfDivisors << std::endl;
  return 0;
}
Publicat 01/12/2014 la 14:01
sursa de către utilizator

voturi
1

Acesta este modul cel mai de bază de calcul a divissors numărul:

class PrintDivisors
{
    public static void main(String args[])
    {

    System.out.println("Enter the number");

    // Create Scanner object for taking input
    Scanner s=new Scanner(System.in);

    // Read an int
    int n=s.nextInt();

        // Loop from 1 to 'n'
        for(int i=1;i<=n;i++)
        {

            // If remainder is 0 when 'n' is divided by 'i',
            if(n%i==0)
            {
            System.out.print(i+", ");
            }
        }

    // Print [not necessary]    
    System.out.print("are divisors of "+n);

    }
}
Publicat 02/12/2014 la 03:25
sursa de către utilizator

voturi
0

Acest lucru este ceva ce am venit cu Justin bazat pe un răspuns. S-ar putea necesita unele optimizare.

n=int(input())

a=[]
b=[]

def sieve(n):
    np = n + 1
    s = list(range(np)) 
    s[1] = 0
    sqrtn = int(n**0.5)
    for i in range(2, sqrtn + 1): 
        if s[i]:
            s[i*i: np: i] = [0] * len(range(i*i, np, i))
    return filter(None, s)

k=list(sieve(n))

for i in range(len(k)):
        if n%k[i]==0:
                a.append(k[i])

a.sort()

for i in range(len(a)):
        j=1
        while n%(a[i]**j)==0: 
                j=j+1
        b.append(j-1)

nod=1

for i in range(len(b)):
        nod=nod*(b[i]+1)

print('no.of divisors of {} = {}'.format(n,nod))
Publicat 29/11/2015 la 07:30
sursa de către utilizator

voturi
0

Cred că acest lucru este ceea ce căutați for.I face exact ceea ce ai cerut. Copiați și lipiți-l în Notepad.Save ca * .bat.Run.Enter Number.Multiply procesul de 2 și thats numărul de divisors.I făcut asta intenționat, astfel încât acesta determina divizorii mai rapid:

Pls rețineți că CMD varriable valori de sprijin cant peste 999999999

@echo off

modecon:cols=100 lines=100

:start
title Enter the Number to Determine 
cls
echo Determine a number as a product of 2 numbers
echo.
echo Ex1 : C = A * B
echo Ex2 : 8 = 4 * 2
echo.
echo Max Number length is 9
echo.
echo If there is only 1 proces done  it
echo means the number is a prime number
echo.
echo Prime numbers take time to determine
echo Number not prime are determined fast
echo.

set /p number=Enter Number : 
if %number% GTR 999999999 goto start

echo.
set proces=0
set mindet=0
set procent=0
set B=%Number%

:Determining

set /a mindet=%mindet%+1

if %mindet% GTR %B% goto Results

set /a solution=%number% %%% %mindet%

if %solution% NEQ 0 goto Determining
if %solution% EQU 0 set /a proces=%proces%+1

set /a B=%number% / %mindet%

set /a procent=%mindet%*100/%B%

if %procent% EQU 100 set procent=%procent:~0,3%
if %procent% LSS 100 set procent=%procent:~0,2%
if %procent% LSS 10 set procent=%procent:~0,1%

title Progress : %procent% %%%



if %solution% EQU 0 echo %proces%. %mindet% * %B% = %number%
goto Determining

:Results

title %proces% Results Found
echo.
@pause
goto start
Publicat 07/02/2016 la 21:24
sursa de către utilizator

voturi
1

@Kendall

Am testat codul și a făcut unele îmbunătățiri, acum este chiar mai repede. De asemenea, am testat cu @ هومن جاویدپور cod, acest lucru este, de asemenea, mai rapid decât codul său.

long long int FindDivisors(long long int n) {
  long long int count = 0;
  long long int i, m = (long long int)sqrt(n);
  for(i = 1;i <= m;i++) {
    if(n % i == 0)
      count += 2;
  }
  if(n / m == m && n % m == 0)
    count--;
  return count;
}
Publicat 11/11/2016 la 15:32
sursa de către utilizator

voturi
0

cred ca aceasta va fi la îndemână precum și precisă

script.pyton

>>>factors=[ x for x in range (1,n+1) if n%x==0] print len(factors)

Publicat 23/01/2017 la 15:57
sursa de către utilizator

voturi
0

Încercați ceva de-a lungul acestor linii:

int divisors(int myNum) {
    int limit = myNum;
    int divisorCount = 0;
    if (x == 1) 
        return 1;
    for (int i = 1; i < limit; ++i) {
        if (myNum % i == 0) {
            limit = myNum / i;
            if (limit != i)
                divisorCount++;
            divisorCount++;
        }
    }
    return divisorCount;
}
Publicat 23/01/2017 la 16:01
sursa de către utilizator

voturi
0

Puteți precompute amorse până la rădăcina Sqaure a maxim posibil N și calcula exponentul fiecărui factor primordial al unui număr. Numărul de divizori de n (n = p1 ^ p2 ^ b ^ p3 c ...) este (a + 1) (b + 1) (c + 1) pentru că este la fel ca și numără modul de a combina prim un număr de acești factori (iar acest lucru va conta numărul de divizori). Acest lucru este foarte rapid dacă ai precompute numerele prime

Mai multe informatii detaliate despre această metodă:

https://mathschallenge.net/library/number/number_of_divisors

https://www.math.upenn.edu/~deturck/m170/wk2/numdivisors.html

http://primes.utm.edu/glossary/xpage/tau.html

#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;

int divisors_count(const vector<int>& primes, int n)
{
    int divisors = 1;
    for (int i = 0; i < primes.size(); ++i) {
        int factor = primes[i];
        int factor_exponent = 0;
        while (n % factor == 0) {
            ++factor_exponent;
            n /= factor;
        }
        divisors *= (factor_exponent + 1);
    }
    if (n > 1) 
        return 2*divisors; // prime factor > sqrt(MAX_N)
    return divisors;
}

int main()
{
    const int MAX_N = 1e6;
    int max_factor = sqrt(MAX_N);

    vector<char> prime(max_factor + 1, true);
    for (int i = 3; i <= max_factor; i += 2) {
        if (prime[i]) {
            for (int j = 3*i; j <= max_factor; j += 2*i) {
                prime[j] = false;
            }   
        }
    }

    vector<int> primes;
    primes.reserve(max_factor/2);
    primes.push_back(2);
    for (int i = 3; i <= max_factor; i += 2) {
        if (prime[i]) {
            primes.push_back(i);
        }
    }

    int n;
    while (cin >> n) {
        cout << divisors_count(primes, n) << endl;
    }
}
Publicat 17/12/2017 la 15:40
sursa de către utilizator

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more