![[java] 백준 1456번 문제(거의 소수)](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQlV8i%2FbtsNcY18IzY%2F2mCKZXY3XFKPiLSRIpzdfK%2Fimg.png)
[java] 백준 1456번 문제(거의 소수)자료구조 & 알고리즘/BOJ2025. 4. 9. 12:00
Table of Contents
원본 링크 : https://www.acmicpc.net/problem/1456
문제설명
소스코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Boj_1456
{
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
long a = Long.parseLong(st.nextToken());
long b = Long.parseLong(st.nextToken());
int max = (int)Math.sqrt(b) + 1;
boolean[] isPrime = new boolean[max];
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for(int i = 2; i * i < max; i++)
if(isPrime[i])
for(int j = i * i; j < max; j += i)
isPrime[j] = false;
int count = 0;
for (int i = 2; i < max; ++i)
{
if (!isPrime[i]) continue;
long value = (long) i * i;
while (value <= b)
{
if (value >= a) ++count;
if (value > b / i) break;
value *= i;
}
}
System.out.print(count);
}
}
설명
- A ≤ p^k ≤ B(p는 소수, k >= 2)를 만족하는 수를 찾는 문제
- A와 B가 10^14(=100,000,000,000,000)이기 때문에 long으로 처리해야한다.
- 에라토스테네스의 체를 사용하지만, 진짜 소수를 찾는 것이 아니므로 배열의 숫자가 int 범위를 초과할 필요가 없다.
"N까지 소수를 구해야 한다면, boolean[N + 1] 크기의 배열을 만들어야 하는 것 아닌가요?"
"근데 어떻게 √N + 1만큼의 배열만 선언하고도 소수를 구할 수 있는 거죠?"
이 말이 맞는 경우도 있고, 아닌 경우도 있다.
진짜 소수 전체가 필요한지, 아니면 일부 소수만 필요한지"에 따라 달라진다.
우리가 찾는 건 거의 소수다. 즉, 어떤 수 p^k (단, k ≥ 2)가 주어진 범위 A ~ B에 있는지를 찾는 것이다.
그럼 여기서 중요한 점
- p^k <= B일 때 가능한 p의 최대값은?
- 이걸 k=2일 때 기준으로 보면, → p^2 ≤ B → p ≤ √B
즉, 어떤 소수 p에 대해서 p^2부터 계산할 거니까, p는 최대 √B까지만 보면 되는 것이다.
지수가 커질수록 밑은 작아져야 함
p^2 ≤ B일 때 → p ≤ √B
p^3 ≤ B일 때 → p ≤ B^(1/3)
p^4 ≤ B일 때 → p ≤ B^(1/4)
...
즉, k가 커지면 커질수록 p는 점점 더 작아져야 한다.
→ 그러니까 p가 클 수 있는 한계는 k = 2일 때뿐이다.
→ 그때 가장 큰 p가 √B인 것이다.
때문에 아래처럼 작성해도 된다.
int max = (int)Math.sqrt(b);
boolean[] isPrime = new boolean[max + 1];
그 다음으로 문제가 되는 부분은 아래의 코드이다.
int count = 0;
for(int i = 2; i < max; ++i)
{
for(int j = 2; j < 100; ++j)
{
double pow = Math.pow(i, j);
if (pow > b) break;
if (isPrime[i] && pow >= a) ++count;
}
}
이 코드는 내가 처음에 작성한 코드인데 문제를 맞추는데는 전혀 문제없지만, j의 범위를 그냥 무작정 크게한 것이 마음에 걸렸다.
그리고 Math.pow()는 double을 반환하기 때문에 정확한 정수값이 아닐 수 있다. (부동소수점 오차)
그래서 아래와 같이 바꿨다.
int count = 0;
for (int i = 2; i < max; ++i)
{
if (!isPrime[i]) continue;
long value = (long) i * i;
while (value <= b)
{
if (value >= a) ++count;
if (value > b / i) break; // 오버플로우 방지
value *= i;
}
}
오버플로우 방지
우리가 실제로 확인하고 싶은 것은 value * i > b 이다.
하지만 이렇게 직접 곱하면 오버플로우가 발생할 수 있다.
그래서 식을 변형한 것이다.
value * i > b
value > b / i
'자료구조 & 알고리즘 > BOJ' 카테고리의 다른 글
[java] 백준 1850번 문제(최대 공약수 구하기) (0) | 2025.04.11 |
---|---|
[java] 백준 1747번 문제(소수&팰린드롬) (0) | 2025.04.10 |
[java] 백준 1541번 문제(잃어버린 괄호) (0) | 2025.04.08 |
[java] 백준 1931번 문제(회의실 배정) (0) | 2025.04.08 |
[java] 백준 1715번 문제(카드 정렬하기) (0) | 2025.04.07 |