하나 이상의 연속된 소수의 합으로 나타낼 수 있는 자연수들이 있다. 몇 가지 자연수의 예를 들어 보면 다음과 같다.
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
20
예제 출력 1
0
예제 입력 2
3
예제 출력 2
1
예제 입력 3
41
예제 출력 3
3
예제 입력 4
53
예제 출력 4
2
얼마 전에 에라토스테네스의 체 문제 풀었던 거 복습할 겸 비슷한 문제를 한 번 풀어봤다.
2부터 N까지의 모든 소수를 구하고, 오름차순으로 리스트에 저장한다.
그 후엔 연속 합을 구해야 하니 투 포인터로 접근하면 된다. 연속 합이 N보다 크거나 같으면 연속 합을 줄여서 다시 탐색해야 하니 오른쪽 포인터를 1 증가시키고, 연속 합이 N보다 작으면 연속 합이 늘려서 다시 탐색해야 하니 왼쪽 포인터를 1 증가시킨다.
에라토스테네스의 체만 알면 어렵지는 않은 문제였다.
딱 알면 풀고, 모르면 영원히 시간 초과밖에 안 나는 문제 느낌.
import java.io.*;
import java.util.*;
class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
if (N == 1) {
System.out.println(0);
return;
}
boolean[] isPrime = new boolean[N + 1];
Arrays.fill(isPrime, true);
for (int i = 2; i <= Math.sqrt(N); i++) {
for (int j = i * 2; j <= N; j += i) {
isPrime[j] = false;
}
}
List<Integer> primeNum = new ArrayList<>();
for (int i = 2; i <= N; i++) {
if (isPrime[i]) {
primeNum.add(i);
}
}
int len = primeNum.size();
int sum = primeNum.get(0);
int count = 0;
for (int i = 0, j = 0; i <= j && j < len;) {
if (sum == N) {
count++;
if (j + 1 == len) {
break;
}
sum += primeNum.get(++j);
} else if (sum < N) {
if (j + 1 == len) {
break;
}
sum += primeNum.get(++j);
} else {
sum -= primeNum.get(i++);
}
}
System.out.println(count);
}
}