
하나 이상의 연속된 소수의 합으로 나타낼 수 있는 자연수들이 있다. 몇 가지 자연수의 예를 들어 보면 다음과 같다.
3 : 3 (한 가지)
41 : 2+3+5+7+11+13 = 11+13+17 = 41 (세 가지)
53 : 5+7+11+13+17 = 53 (두 가지)
하지만 연속된 소수의 합으로 나타낼 수 없는 자연수들도 있는데, 20이 그 예이다. 7+13을 계산하면 20이 되기는 하나 7과 13이 연속이 아니기에 적합한 표현이 아니다. 또한 한 소수는 반드시 한 번만 덧셈에 사용될 수 있기 때문에, 3+5+5+7과 같은 표현도 적합하지 않다.
자연수가 주어졌을 때, 이 자연수를 연속된 소수의 합으로 나타낼 수 있는 경우의 수를 구하는 프로그램을 작성하시오.
첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 4,000,000)
첫째 줄에 자연수 N을 연속된 소수의 합으로 나타낼 수 있는 경우의 수를 출력한다.
정보
목표
제약 조건
알고리즘
탐색 과정
종료 조건
일반적으로 소수를 판별하는 방법은 다음과 같다.
이를 해결하기 위해 고안된 알고리즘이 에라토스테네스의 체이다.
해당 알고리즘의 원리는 다음과 같다
여기서 두 가지 의문이 들 수 있겠다.
1. 왜 2부터 N의 제곱근 까지만 반복하지?
2. 왜 배수들을 처리할 때 시작점이 i * i 부터지?
1번의 이유는 다음과 같다.
어떤 수 x가 소수가 아니라면, x는 두 수 a와 b의 곱으로 표현 할 수 있을것이다.
해당 식에서, a와 b중 적어도 하나는 보다 작거나 같아야 한다.
만약 a > 이고 b > 라면, 이 되어 x가 N보다 커지기 때문이다.
따라서 이전에 이미 약수들로 인해 소수로 걸러지게 된다.
2번의 이유는 다음과 같다.
이미 걸러진 배수는 처리할 필요가 없다.
예시를 보자면,
따라서 일 경우 는 이미 걸러져 있게 된다.
즉 부터 시작해 중복 계산을 피할 수 있게 하는 것이다.
해당 알고리즘의 코드는 다음과 같다.
public void prime(int N){
list = new ArrayList<>();
isPrime = new boolean[N + 1];
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= N; i++) {
if(isPrime[i]) {
for (int j = i * i; j <= N; j += i) {
isPrime[j] = false;
}
}
}
for (int i = 2; i <= N; i++) {
if(isPrime[i]) {
list.add(i);
}
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
public class BOJ1644 {
static int N;
static boolean[] isPrime;
static ArrayList<Integer> list = new ArrayList<>();
private static void solution() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
//에라토스테네스의 체
isPrime = new boolean[N + 1];
Arrays.fill(isPrime, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i * i <= N; i++) {
if(isPrime[i]) {
for (int j = i * i; j <= N; j += i) {
isPrime[j] = false;
}
}
}
for (int i = 2; i <= N; i++) {
if(isPrime[i]) {
list.add(i);
}
}
//투 포인터 활용
int start = 0, end = 0, current_sum = 0, result = 0;
while (end < list.size()) {
if (current_sum < N) {
current_sum += list.get(end++);
} else if (current_sum > N) {
current_sum -= list.get(start++);
} else{
result++;
current_sum += list.get(end++);
}
}
while(current_sum >= N && start < list.size()) {
if (current_sum == N) {
result++;
}
current_sum -= list.get(start++);
}
System.out.println(result);
}
public static void main(String[] args) throws IOException {
BOJ1644.solution();
}
}
