문제 링크
1456번: 거의 소수
어떤 수가 소수의 N제곱(N ≥ 2) 꼴일 때, 그 수를 거의 소수라고 한다. 두 정수 A와 B가 주어지면, A보다 크거나 같고, B보다 작거나 같은 거의 소수가 몇 개인지 출력한다.
www.acmicpc.net
문제 해설
수의 범위가 주어졌을 때 해당 범위 내에서 소수의 거듭제곱이 되는 수의 개수를 찾는 문제다.
범위가 최대 \(10^{14}\)이지만 소수는 최대 \(10^{7}\) 범위 내에서만 찾으면 된다. 소수의 거듭제곱이 범위 내에 포함되는지를 찾아야하는데 \(10^{7}=\sqrt{10^{14}}\)이므로 \(10^7\)을 초과하는 소수는 거듭제곱을 하면 범위를 벗어나기 때문이다. 따라서 우선 에라토스테네스의 체를 이용하여 \(\sqrt{B}\) 이하인 소수를 모두 구한다.(코드의 getPrimes()
메소드)
이후 구해진 소수들을 순회하면서 주어진 범위 내에 소수의 거듭제곱이 포함되는지 확인해야하는데 여기서 주의해야할 점이 있다. \(10^7\)을 세제곱하면 \(10^{21}\)이 되어 Long 타입의 범위를 아득히 초과하기 때문에 오버플로가 발생할 수 있다. 따라서 오버플로를 방지하기 위한 별도의 로직이 필요하다.
오버플로를 방지하기 위한 로직은 여러 방법이 있겠지만, 필자의 경우에는 소수가 \(\left \lfloor \sqrt[3]{10^{14}} \right \rfloor=46,415\)보다 크면서 현재 검사하는 수가 \(10^{7}\)보다 클 때 다음 소수로 넘어가는 방식으로 구현했다.
Code
import kotlin.math.sqrt
fun main() = with(System.`in`.bufferedReader()) {
val (a, b) = readLine().split(' ').map { it.toLong() }
val primeNumbers = getPrimes(b)
var count = 0
for (prime in primeNumbers) {
var num = prime
while (num <= b) {
if (prime > 46415 && num > 10_000_000) break
num *= prime
if (num in a..b) count++
}
}
println(count)
}
private fun getPrimes(b: Long): List<Long> {
val isPrime = BooleanArray(sqrt(b.toDouble()).toInt() + 1) { true }
val sqrt = sqrt(isPrime.lastIndex.toDouble()).toInt()
val resultList = mutableListOf<Long>()
isPrime[0] = false
isPrime[1] = false
for (i in 2..sqrt) {
if (isPrime[i]) {
for (j in i * i..isPrime.lastIndex step i) isPrime[j] = false
}
}
for (i in isPrime.indices) {
if (isPrime[i]) resultList.add(i.toLong())
}
return resultList
}
참조 링크
[Kotlin/Java] 소수 찾기와 에라토스테네스의 체
소수를 판별하는 기본적인 방법 소수(prime number, 素數)는 1과 자기 자신만으로 나누어 떨어지는 1보다 큰 자연수를 의미한다. 예를 들면 2, 3, 5, 7 ... 등이 있다. 어떤 수 \(x\)가 주어졌을 때 \(x\)가
colabear754.tistory.com
'Algorithm > BOJ' 카테고리의 다른 글
[Kotlin] 백준 25325 : 학생 인기도 측정 (0) | 2022.12.25 |
---|---|
[Kotlin] 백준 1092 : 배 (0) | 2022.12.24 |
[Kotlin] 백준 25192 : 인사성 밝은 곰곰이 (0) | 2022.12.21 |
[Kotlin] 백준 14277 : 등차 수열과 등비 수열 (0) | 2022.12.21 |
[Kotlin] 백준 9935 : 문자열 폭발 (0) | 2022.12.19 |
댓글