[Gold III]
https://www.acmicpc.net/problem/1644
1644번: 소수의 연속합
첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 4,000,000)
www.acmicpc.net
풀이 1
보자마자, Prefix Sum 문제라고 생각했다.
먼저 에라토스테네스의 체를 이용해 입력값인 N까지의 수 중 소수를 구하고,
그 소수들의 리스트를 이용해 prefix sum 리스트를 만든 후,
Two Pointer 기법을 이용해 부분합의 값이 N과 동일한 지 확인하는 방법.
시간은 충분했으나,
MLE. (Memory Limit Exceed.)
N = int(input())
nums = {i: 0 for i in range(2, N+1)}
# 에라토스테네스의 체
for i in nums:
if nums[i] > 0:
continue
elif i > N:
break
k = 1
while True:
k += 1
j = i*k
if j > N:
break
nums[j] += 1
primes = []
for i in nums:
if nums[i] == 0:
primes.append(i)
# prefix sum of primes
sum_prime = [0, primes[0]]
for i in range(1, len(primes)):
sum_prime.append(sum_prime[i] + primes[i])
# two pointer of index
p1 = 0
p2 = 0
result = 0
while True:
S = sum_prime[p2] - sum_prime[p1]
if S == N:
p2 += 1
result += 1
elif S < N:
p2 += 1
elif S > N:
p1 += 1
if p1 >= len(sum_prime) or p2 >= len(sum_prime):
break
print(result)
풀이 2
메모리 사용을 줄이기 위해, sum_prime
리스트를 따로 만들지 않고, primes
리스트에서 List Slicing으로 부분합을 처리하고,
처음에 에라토스테네스의 체로 소수를 판정할 때, Dictionary가 아닌, True&Flase를 저장하는 배열로 처리하였다.
AC.
N = int(input())
nums = [True] * (N+1)
nums[0] = False
nums[1] = False
# 에라토스테네스의 체
for i in range(2, N+1):
if not nums[i]:
continue
elif i > N:
break
k = 1
while True:
k += 1
j = i*k
if j > N:
break
nums[j] = False
primes = []
for i, flag in enumerate(nums):
if flag:
primes.append(i)
# two pointer of index
p1 = 0
p2 = 0
result = 0
while True:
S = sum(primes[p1:p2])
if S == N:
p2 += 1
result += 1
elif S < N:
p2 += 1
elif S > N:
p1 += 1
if p1 > len(primes) or p2 > len(primes):
break
print(result)