Processing math: 100%
 

골드바흐의 추측을 이용해 정수 n을 k개의 소수 합으로 표현하기

25309번: K개의 소수 (acmicpc.net)

 

정수 n을 k개의 소수 합으로 표현하라는 문제

 

여기서 핵심은 서로 다른 k개의 소수가 아니라, 같은 소수를 사용해도 좋다.

 

그리고 문제는 n이 최대 108이고 k는 최대 10000이라 단순한 방법으로는 어렵다

 

먼저 생각할 수 있는 것은 가장 작은 소수가 2이기 때문에, 2를 k개 사용하여 2k가 만들 수 있는 정수의 최솟값이다.

 

따라서 n < 2k이면 분해하는 것이 불가능하고, n >= 2k이면 일단 분해하는 것이 가능하다.

 

n,k = map(int,input().split())

if n < 2*k:
    
    print(-1)

 

 

만약 k = 1이면 n 자체로 소수인지 아닌지 판단하면 된다.

 

O(n)에 소수 판단할 수 있다.

 

def is_prime(n):
    
    for i in range(2,int(n**(1/2))+1):
        
        if n % i == 0:
            
            return False
    
    return True

 

 

다음 k = 2이면, n이 짝수인가 홀수인가에 따라 다르다.

 

여기서 골드바흐의 추측은 

 

"2보다 큰 모든 짝수는 두 소수의 합으로 나타낼 수 있다"

 

증명되지는 않았지만 다행히 일반적으로 다루는 정수 범위 내에서는 참이다.

 

n >= 2k이고, k = 2일때 n이 짝수라면 골드바흐의 추측에 의해 가능하다.

 

이 경우 두 소수를 아무거나 찾아야한다.

 

def represent_two_prime(n):
    
    for i in range(2,n+1):
        
        if is_prime(i) and is_prime(n-i):
            
            return i

 

 

O(NN)처럼 보이긴 한데, 실제로 보면 n이 최대 108이면 최대 i = 1039정도에서 찾을 수 있다.

 

그러다보니까 아무거나 하나를 찾는다면 실제로는 O(N)정도 되는듯

 

이번에는 n >= 2k이고 k = 2에서 n이 홀수라면 이야기가 조금 다르다.

 

소수는 유일하게 2만 짝수이고, 나머지는 홀수라는 특징이 있다.

 

그런데, 짝수 + 짝수 = 짝수, 짝수 + 홀수 = 홀수, 홀수 + 홀수 = 짝수 라는 특징이 있다.

 

그러다보니 n이 홀수인데 2개의 소수 합으로 나타낼려면, 짝수 + 홀수로 나타낼수밖에 없는데, 

 

유일하게 2만 짝수이므로 2를 반드시 사용해야한다.

 

따라서, n - 2가 소수이면 2와 n-2의 합으로 나타낼 수 있고, n-2가 소수가 아니라면 분해하는 것이 불가능하다.

 

    elif k == 2:
        
        if n % 2 == 0:
            
            a = represent_two_prime(n)
            print(a,n-a)
        
        else:
            
            if is_prime(n-2):
                
                print(2,n-2)
            
            else:
                
                print(-1)

 

 

마지막으로 n >= 2k인데 k >= 3인경우는 반드시 k개의 소수 합으로 분해할 수 있다.

 

어떻게 가능한가?

 

n이 짝수라면 n - 2(k-2)도 짝수이다. 

 

왜냐하면 n = 2m이면 2m-2(k-2) = 2(m-(k-2))는 짝수니까

 

그러므로 2를 먼저 k-2번 더하고 나서, 나머지 2개는 n-2(k-2)는 짝수이므로, 이를 골드바흐의 추측에 따라 2개의 소수 합으로 분해하면 된다.

 

n이 홀수라면 n - 3 - 2(k-3)도 짝수이다.

 

n = 2m+1이면 2m-2 - 2(k-3) = 2(m-1-(k-3))이므로 짝수

 

그러므로 2를 먼저 k-3번 더하고 나서 나머지 3개중 1개는 3을 사용하고 남은 2개는 n-3-2(k-3)이 짝수니까

 

골드바흐의 추측에 따라 2개의 소수 합으로 분해하면 된다

 

def is_prime(n):
    
    for i in range(2,int(n**(1/2))+1):
        
        if n % i == 0:
            
            return False
    
    return True

def represent_two_prime(n):
    
    for i in range(2,n+1):
        
        if is_prime(i) and is_prime(n-i):
            
            return i

n,k = map(int,input().split())

#가장 작은 소수는 2이므로, k개의 소수로 만들 수 있는 가장 작은 정수는 2k
if n < 2*k:
    
    print(-1)

else:
    
    #n을 1개의 소수로 만들 수 있는가?
    #n 자체가 소수인지 아닌지 판단
    if k == 1:
        
        if is_prime(n):
            
            print(n)
        
        else:
            
            print(-1)
    
    #2개의 소수로 만들 수 있는가?
    elif k == 2:
        
        #n이 짝수이면 2보다 큰 모든 짝수는 2개의 소수 합으로 분해할 수 있다
        if n % 2 == 0:
            
            a = represent_two_prime(n)
            print(a,n-a) #아무거나 빠르게 하나를 찾는다
        
        else:
            
            #n이 홀수라면, 짝수 + 홀수 = 홀수이고 소수중 2만이 유일하게 짝수이므로
            #2를 반드시 사용해야하고, 나머지 n-2가 소수인지 아닌지 판단
            if is_prime(n-2):
                
                print(2,n-2)
            
            else:
                
                print(-1)
        
    else: #n을 3개 이상의 소수로 만들 수 있는가?
        
        if n % 2 == 0:
            
            #n이 짝수이면 n - 2(k-2)도 짝수이다.
            #따라서 2를 k-2번 사용하고, 나머지 2개는 n-2(k-2)를 2개의 소수 합으로 분해
            for _ in range(k-2):
                
                print(2,end=' ')
            
            a = represent_two_prime(n-2*(k-2))
            print(a,end=' ')
            print(n-2*(k-2)-a,end=' ')
        
        else:
            
            #n이 홀수이면 n-3-2(k-3)도 짝수이다.
            #따라서 2를 k-3번 사용, 3을 1번 사용, 나머지 2개는 n-3-2(k-3)을 2개의 소수 합으로 분해
            for _ in range(k-3):
                
                print(2,end=' ')
            
            print(3,end=' ')
            a = represent_two_prime(n-3-2*(k-3))
            print(a,end=' ')
            print(n-3-2*(k-3)-a,end=' ')

 

 

728x90