Fatorização em primos

Qualquer inteiro positivo n ≥ 2 pode ser representado como um produto de números primos:

2=2=214=2⋅2=2249=7⋅7=7224=2⋅2⋅2⋅3=23⋅3175=3⋅5⋅5=31⋅5284=2⋅2⋅3⋅7=22⋅31⋅71\begin{aligned} 2 &= 2 &&= 2^1 \\ 4 &= 2 \cdot 2 &&= 2^2 \\ 49 &= 7 \cdot 7 &&= 7^2 \\ 24 &= 2 \cdot 2 \cdot 2 \cdot 3 &&= 2^3 \cdot 3^1 \\ 75 &= 3 \cdot 5 \cdot 5 &&= 3^1 \cdot 5^2 \\ 84 &= 2 \cdot 2 \cdot 3 \cdot 7 &&= 2^2 \cdot 3^1 \cdot 7^1 \end{aligned}

Existem muitas aplicações para encontrar os fatores primos de um número. É possível, por exemplo, calcular mais facilmente o número de divisores de um determinado valor, além de obter uma noção clara sobre o máximo divisor comum (GCD) e o mínimo múltiplo comum (LCM) de dois números, entre outras utilidades.

Para representar um número n (por exemplo, 300) como o produto dos seus fatores primos, podemos começar pelo menor número primo p (2) e, caso n seja divisível por p, continuar a dividi-lo por p enquanto for possível (300 / 2 = 150, 150 / 2 = 75).

Em seguida, aumenta-se p em 1 (p = 3) e volta-se a tentar dividir n por este novo valor. Caso seja divisível, dividimos n por p enquanto isso for possível (75 / 3 = 25).

Depois voltamos a aumentar p em 1 (p = 4) e tentamos dividir n por p. Note que não é possível dividir n por números que não são primos, pois n já foi exaustivamente dividido pelos primos menores que 4. No nosso exemplo, 300 é divisível por 4, mas 75 não o é, pois já extraímos todos os fatores 2 de 300 anteriormente. Portanto, se todos os 2s já foram retirados, números como 4, 6, 8 (múltiplos de 2) não irão mais dividir o valor restante. Como seguimos esse processo do menor para o maior número, podemos ter certeza de que só restarão números primos para dividir o valor ainda não decomposto.

No passo seguinte, aumentamos o divisor em 1 novamente (p = 5) e tentamos dividir n pelo novo p (75 / 5 = 5, 5 / 5 = 1). Continuamos assim até que o divisor seja maior do que n\sqrt{n}. Se chegarmos a um ponto em que o divisor seja maior do que n\sqrt{n}, significa que a parte restante de n é um número primo e podemos incluí-lo diretamente na nossa lista de divisores.

Dessa forma, no exemplo dado, 300 pode ser representado como 2⋅2⋅3⋅5⋅52 \cdot 2 \cdot 3 \cdot 5 \cdot 5.

n = ...                              # Representar n como um produto de primos
p, divisors, powers = 1, [], []      # fator primo, divisores e seus expoentes

while p * p <= n:                    # enquanto p <= sqrt(n)
    p += 1                           # adiciona 1 ao fator primo a cada iteração
    if n % p != 0:                   # não faz nada se n não for divisível por p
        continue
    
    divisors.append(p)               # n % p == 0 => adicionar p como fator primo
    powers.append(0)                 # o expoente começa em 0
    while n % p == 0:                # dividir o máximo de vezes possível
        n //= p
        powers[-1] += 1              # aumentar o expoente em 1 a cada divisão

if n > 1:                            # se p > sqrt(n) => n ainda é um fator primo
    divisors.append(n)               # adicionar n como divisor
    powers.append(1)                 # com expoente igual a 1

print(list(zip(divisors, powers)))   # imprimir fatores e seus expoentes

A cada iteração do algoritmo, dividimos o número pelo seu fator primo se for possível, aumentando simultaneamente o expoente a cada divisão realizada.

Vamos agora simular o algoritmo em alguns números:

n = 24
  1. p = 2, n = 24 (aumentámos p de 1 para 2 no início do ciclo)
    n % 2 == 0 ⇒ divisors = [2], powers = [0]
    n //= 2 ⇒ n = 12, powers = [1]
    n //= 2 ⇒ n = 6, powers = [2]
    n //= 2 ⇒ n = 3, powers = [3]

  2. p = 3, n = 3 ⇒ parar o ciclo while pois p * p = 9 é maior que 2

  3. n > 1 ⇒ divisors = [2, 3], powers = [3, 1]

n = 75
  1. p = 2, n = 75

  2. p = 3, n = 75
    n % 3 == 0 ⇒ divisors = [3], powers = [0]
    n //= 3 ⇒ n = 25, powers = [1]

  3. p = 4, n = 25

  4. p = 5, n = 25
    n % 5 == 0 ⇒ divisors = [3, 5], powers = [1, 0]
    n //= 5 ⇒ n = 5, powers = [1, 1]
    n //= 5 ⇒ n = 1, powers = [1, 2]

  5. p * p > n ⇒ parar o ciclo while ⇒ divisors = [3, 5], powers = [1, 2]

n = 84
  1. p = 2, n = 84
    n % 2 == 0 ⇒ divisors = [2], powers = [0]
    n //= 2 ⇒ n = 42, powers = [1]
    n //= 2 ⇒ n = 21, powers = [2]

  2. p = 3, n = 21
    n % 3 == 0 ⇒ divisors = [2, 3], powers = [2, 0]
    n //= 3 ⇒ n = 7, powers = [2, 1]

  3. p * p > n ⇒ parar o ciclo while

  4. n > 1 ⇒ divisors = [2, 3, 7], powers = [2, 1, 1]

n = 31
  1. p = 2, n = 31

  2. p = 3, n = 31

  3. p = 4, n = 31

  4. p = 5, n = 31

  5. p = 6, n = 31

  6. p * p > n ⇒ parar o ciclo while

  7. n > 1 ⇒ divisors = [31], powers = [1]

Desafio

Dado um inteiro n, pede-se para encontrar o seu maior fator primo.

Entrada

A primeira linha da entrada contém um único inteiro n (2 ≤ n ≤ 10910^9).

Saída

O programa deve imprimir o maior fator primo de n.

Exemplos

Entrada

Saída

8

2

24

3

75

5

31

31

Bónus: Por que não verificamos apenas números primos?

Na nossa implementação atual, percorremos todos os números 2, 3, 4, … até n\sqrt{n}. À primeira vista, poderia parecer mais lógico iterar apenas sobre números primos. De facto, pode haver casos em que isso funcione bem. No entanto, gerar todos os números primos até n\sqrt{n} exige mais iterações do que simplesmente verificar se n é divisível por cada inteiro até n\sqrt{n} (mais precisamente, o procedimento demandaria algo em torno de O(n⋅log⁡log⁡n)\mathcal{O}(\sqrt{n} \cdot \log \log \sqrt{n}) para gerar esses primos).

Consegue pensar num cenário em que pré-calcular todos os números primos até certo valor e depois utilizá-los para extrair os fatores primos pudesse ser mais eficiente?

Constraints

Time limit: 1.6 seconds

Memory limit: 512 MB

Output limit: 1 MB