[PS] BOJ 1644 / 소수의 연속합

[PS] BOJ 1644 / 소수의 연속합
문제 링크: https://www.acmicpc.net/problem/1644
Thumbnail: Photo by Ryunosuke Kikuno (Unsplash)

풀이

에라토스테네스의 체를 사용해 $N$까지의 소수를 미리 구하고, 소수들의 배열을 가지고 투 포인터 탐색을 활용해 연속 합을 구하면 됩니다.

에라토스테네스의 체

에라토스테네스의 체는 잘 알려진 소수 판별법으로, 1부터 $N$까지의 범위 안에서 소수를 일괄적으로 구할 때 사용합니다.

이번 문제에서는 에라토스테네스의 체로 소수를 판별한 뒤, 발견한 소수를 다시 배열에 저장합니다. 이후 소수의 연속 합을 계산하기 위해선 소수의 배열이 필요하기 때문입니다.

동시에, 소수를 판별하면서 누적합 배열도 계산했습니다. 하지만, 후술할 투 포인터 탐색을 생각하면 사실 굳이 누적합을 만들지 않고도 적절하게 구현할 수 있습니다.

N = int(input())

primes_acc = [0, ]
sieve = [True] * 4_000_001
sieve[0] = sieve[1] = False

for i in range(2, 2_001): # sqrt(4_000_000) = 2000
    if sieve[i]:
        j = i * 2
        while j <= 4_000_000:
            sieve[j] = False
            j += i
for i in range(4_000_001):
    if sieve[i]:
        primes_acc.append(primes_acc[-1] + i)
primes_cnt = len(primes_acc)

에라토스테네스의 체

투 포인터 탐색

투 포인터 탐색으로, 소수의 누적 합을 계산합니다. start를 기준으로, end를 1씩 늘려가면서 합이 N보다 크거나 같아지는 순간을 찾으면 됩니다.

cnt = 0
for start in range(primes_cnt):
    end = start + 1
    while end < primes_cnt:
        total = primes_acc[end] - primes_acc[start]
        if total > N:
            break
        elif total == N:
            cnt += 1
            break
        end += 1

print(cnt)

투 포인터 탐색

전체 코드

input = open(0).readline
N = int(input())

primes_acc = [0, ]
sieve = [True] * 4_000_001
sieve[0] = sieve[1] = False

for i in range(2, 2_001): # sqrt(4_000_000) = 2000
    if sieve[i]:
        j = i * 2
        while j <= 4_000_000:
            sieve[j] = False
            j += i
for i in range(4_000_001):
    if sieve[i]:
        primes_acc.append(primes_acc[-1] + i)
primes_cnt = len(primes_acc)

cnt = 0
for start in range(primes_cnt):
    end = start + 1
    while end < primes_cnt:
        total = primes_acc[end] - primes_acc[start]
        if total > N:
            break
        elif total == N:
            cnt += 1
            break
        end += 1

print(cnt)

solution.py