골드바흐의 추측을 이용해 정수 n을 k개의 소수 합으로 표현하기
정수 n을 k개의 소수 합으로 표현하라는 문제
여기서 핵심은 서로 다른 k개의 소수가 아니라, 같은 소수를 사용해도 좋다.
그리고 문제는 n이 최대 $10^{8}$이고 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(\sqrt{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(N\sqrt{N})$처럼 보이긴 한데, 실제로 보면 n이 최대 $10^{8}$이면 최대 i = 1039정도에서 찾을 수 있다.
그러다보니까 아무거나 하나를 찾는다면 실제로는 $O(\sqrt{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=' ')
'정수론' 카테고리의 다른 글
10진수를 다른 진법으로 바꾸는 방법 (0) | 2024.09.01 |
---|---|
2^30으로 나눈 나머지로 2^5으로 나눈 나머지를 구할 수 있을까 (0) | 2024.08.10 |
약수를 세는 것보다 배수를 세는 것이 더 쉽다(홀수인 약수의 합, 유일한 소인수의 개수를 구하는 방법) (0) | 2024.04.11 |
팩토리얼(factorial)의 소수 모듈로 곱셈의 역원(modulo inverse)을 구하는 기본적인 테크닉 (0) | 2024.04.05 |
100부터 1000000000000000까지 모든 정수의 최대공약수는 어떻게 구할 수 있을까 (0) | 2024.03.29 |