문제
https://www.acmicpc.net/problem/1644
1644번: 소수의 연속합
첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 4,000,000)
www.acmicpc.net
문제 요약
자연수 N이 주어졌을 때, 연속된 소수의 합으로 나타낼 수 있는 경우의 수를 출력한다.
ex)
3 = 3 => 한 가지
41 = 2 + 3 + 5 + 7 + 11 + 13 = 11 + 13 + 17 = 41 => 세 가지
코드
import math
n = int(input())
# 체 알고리즘을 이용하여 소수로 구성된 리스트 구하기
pri_arr = [True for _ in range(n + 1)] # n 까지 소수인지 아닌지를 판별하는 리스트 (초기: 소수 = True)
for i in range(2, int(math.sqrt(n) + 1)): # 2부터 n의 제곱근까지 모든 수를 확인
if pri_arr[i] == True: # 아직까지 소수가 아닌 것으로 판별되지 않은 경우
# i의 배수에 해당하는 값을 모두 소수가 아닌 것(False)으로 변경
j = 2
while i * j <= n:
pri_arr[i * j] = False
j += 1
arr = [] # n까지의 모든 소수를 저장하는 리스트
for i in range(2, n + 1):
if pri_arr[i]:
arr.append(i)
ans = 0
# 투 포인터 방식으로 연속된 소수의 합으로 나타낼 수 있는 경우의 수 탐색
left = 0
right = 0
while right <=len(arr): # 오른쪽 포인터가 arr의 인덱스를 벗어나면 종료
# 이번 탐색에서 투포인터가 가리키는 범위 left ~ right 인덱스에 해당하는 연속된 소수의 합
tmp_sum = sum(arr[left:right])
if tmp_sum == n: # n 이면
ans += 1 # 경우의 수 증가
# 다음 탐색을 위한 투포인터의 범위 이동
left += 1
right += 1
elif tmp_sum < n: # n보다 작으면
right += 1 # 다음 탐색을 위한 투포인터의 범위 증가
else:
left += 1 # 다음 탐색을 위한 투포인터의 범위 감소
print(ans)
코드 설명
1. 체 알고리즘을 통해 n 이하의 자연수 중 소수인 자연수들로 구성된 리스트 arr을 생성한다.
< 체 알고리즘을 사용하지 않고 n이 소수인지 아닌지 구별하는 방법 >
- n을 2보다 크고 n보다 같거나 작은 모든 자연수로 나눠 나머지가 0인 경우가 없다면 소수이다.
=> 시간 초과가 발생한다.
< 체 알고리즘을 사용하여 n이 소수인지 아닌지 구별하는 방법 >
- n까지 소수인지 아닌지를 판별하는 크기 n + 1의 Boolean형 배열 pri_arr을 생성한다. (0 ~ n)
- 배열의 초기값은 모두 소수라고 생각한다. (True)
- 2부터 n의 제곱근까지 모든 수 i에 대해 i의 배수에 해당하는 모든 값을 소수가 아니라고 체크한다. (False)
- 위 과정을 수행했을 때, pri_arr[n]이 True라면 소수, 도중에 변경되어 False라면 소수가 아니다.
=> n 뿐만 아니라 n이하의 값까지 소수인지 아닌지 한 번에 알 수 있으므로 시간 초과가 발생하지 않는다.
2. 투포인터 탐색 알고리즘을 이용하여 arr연속된 소수의 합으로 나타낼 수 있는 경우의 수를 탐색한다.
+ left, right 포인터를 조건에 맞게 이동시키며 범위를 변경한다.
3. 탐색에서 찾은 경우의 수를 출력한다.
'Algorithm Problems > 투 포인터' 카테고리의 다른 글
[백준/C++] 7453번: 합이 0인 네 정수 (0) | 2024.03.20 |
---|---|
[백준/Python] 2470번: 두 용액 (1) | 2023.11.08 |
[백준/Python] 26091번: 현대모비스 소프트웨어 아카데미 (1) | 2023.09.24 |
[백준/Python] 3151번: 합이 0 (0) | 2023.09.23 |
[백준/Python] 3273번: 두 수의 합 (0) | 2023.09.18 |