Diamond/Diamond V

BOJ 4149 - 큰 수 소인수분해 (Python3)

nflight11 2022. 12. 1. 01:02

아마 모두의 첫 다이아몬드 티어가 아닐까.

소수 판정법과 소인수분해에 관해서는 거의 마법이나 다름없는 두 가지 알고리즘을 잘 쓰면 된다.

밀러-라빈 소수판정법과 폴라드-로 소인수분해 알고리즘. 작동 방식만 알고 있으면 그리 어렵지 않게 풀 수 있다.

그 작동 방식을 이해하는 것이 최소 다이아몬드라는 것은 잊어 두자.

 

그럼 본격적으로 풀이에 돌입해 보자.


문제

큰 수를 소인수분해 해보자.

 

입력

입력은 한 줄로 이루어져 있고, 소인수분해 해야 하는 수가 주어진다. 이 수는 1보다 크고, \(2^{62}\)보다 작다.

 

예제 입력)

18991325453139

 

출력

입력으로 주어진 양의 정수를 소인수분해 한 뒤, 모든 인수를 한 줄에 하나씩 증가하는 순서로 출력한다.

 

예제 출력)

3
3
13
179
271
1381
2423

 


내 코드

from random import randrange
from sys import setrecursionlimit
pli = [2,3,5,7,11,13,17,19,23,29,31,37,41,43]
setrecursionlimit(10**6)

# Miller-Rabin Test
def power(x,y,p):
    if y<2: return (x**y)%p
    else:
        d = y//2
        if y%2 == 0: return (power(x,d,p)**2)%p 
        else: return (x*(power(x,d,p))**2)%p
def miller_rabin(n,a):
    r,d = 0,n-1
    while d%2 == 0: r += 1; d //= 2
    x = power(a,d,n)
    if x == 1 or x+1 == n: return True
    for i in range(0, r-1):
        x = power(x,2,n)
        if x+1 == n: return True
    return False
def isprime(n):
    if n in pli: return True
    if n == 1 or n%2 == 0: return False
    for p in pli:
        if not miller_rabin(n,p): return False
    return True

# Pollad-Rho algorithm
def gcd(a,b):
    if a<b: a,b = b,a
    while b != 0: a,b = b,a%b
    return a
def rho(n):
    if isprime(n): return n
    if n == 1: return 1
    if n%2 == 0: return 2
    x,c,d = randrange(2,n),randrange(1,n),1
    y = x
    while d == 1:
        x = ((x**2%n)+c)%n
        y = ((y**2%n)+c)%n
        y = ((y**2%n)+c)%n
        d = gcd(n,abs(x-y))
        if d == n: return rho(n)
    if isprime(d): return d
    else: return rho(d)

# Answer Code
n = int(input())
li = []
while n != 1:
    d = rho(n)
    li.append(d)
    n //= d
li.sort()
for i in li: print(i)

 

역시 다이아몬드. 코드가 길고 길어서 끝이 없다.

첫 번째와 두 번째, 밀러-라빈과 폴라드-로에 관한 해설은 해당 포스트에 자세하게 적혀 있으니 그 포스트를 참조 바란다.

 

큰 수의 소인수분해 시 재귀가 끝없이 벌어질 수 있으니 미리 재귀 한도를 setrecursionlimit를 이용하여 1백만 번으로 높여 두자.

그게 없어도 통과가 될 수 있으나, 되지 않을 확률도 0은 아니기 때문에 미리 세팅하여 두는 것이 낫다. 안 해 두어 나쁠 것도 없다.

 

Answer Code에서, li는 소인수를 저장하는 배열이 될 것이다.

rho(n)은 n의 임의의 소인수를 뱉는 코드이기 때문에, 순서대로 정렬된다는 보장이 전혀 없다.

따라서 모든 공정이 마쳐진 후 리스트의 정렬은 필수불가결하다. 그렇지 않는다면 맞게 짰는데 왜 틀렸는지 되뇌이게 될 것이다.

 

이로서 4149번의 풀이를 마친다.

그럼, 오늘도 당신의 코딩 실력이 상승하기를.

728x90