JAVA 알고리즘/유형 문제

[백준 1644 java 자바]소수의 연속합 - 투포인터(부분합 효율성)

nomoreFt 2022. 10. 18. 23:48

[Gold III] 소수의 연속합 - 1644

문제 링크

성능 요약

메모리: 22888 KB, 시간: 1988 ms

분류

수학(math), 정수론(number_theory), 소수 판정(primality_test), 에라토스테네스의 체(sieve), 두 포인터(two_pointer)

문제 설명

하나 이상의 연속된 소수의 합으로 나타낼 수 있는 자연수들이 있다. 몇 가지 자연수의 예를 들어 보면 다음과 같다.

  • 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,3,4,5의 배열 -> 소수 배열 로 바뀐 것 뿐이다.

소수 배열을 구해야 하는 조건만 추가 됐다. 부분합 투포인터가 이해가 되지 않는다면 이전 문제들을 참고하시면 된다.


  • 먼저 문제의 숫자 Math.sqrt(N) 까지 소수 배열을 구한다.
  • 소수는 1과 자기자신만으로 나눠지는 숫자이다.
  • 제곱근으로 구하는 이유는 11을 예로 들면, 6 이상의 숫자로 11을 나눠봐야 어차피 나눠지지 않기 때문이다. (나머지가 딱 0으로 나뉘지 않음) 그래서 절반쯤까지 한다.

투포인터 연속합 참고 : https://nomoreft.tistory.com/m/101


코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

class Main {
    static ArrayList<Integer> arr = new ArrayList<>();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        arr.add(2);
        for (int i = 3; i <= N; i++) {
            isPrime(i);
        }
        int arrSize = arr.size();
        int left = 0,right = 0,sum = 0,cnt =0;
        while (true) {
            if (sum >= N) {
                sum -= arr.get(left++);
            }else if(right == arrSize) break;
            else{
                sum += arr.get(right++);
            }
            if (sum == N) {
                cnt++;
            }
        }
        System.out.println(cnt);
    }
    static void isPrime(int x) {
        for (int i = 2; i <= Math.sqrt(x); i++) {
            if (x % i == 0) {
                return;
            }
        }
        arr.add(x);
    }
}