문제
- 문제 링크
BOJ 27519 - 소수의 합
함수 $f(n)$을 "$n$을 $0$개 이상의 소수의 합으로 표현하는 경우의 수" 라고 정의하자.
$T$개의 $n$이 주어질 때, 각 $n$에 맞는 $f(n)$의 값을 출력해보자.
TL : $3$ sec, ML : $128$ MB
$1 ≤ T ≤ 10,000$ $0 ≤ n_i ≤ 100,000$
알고리즘 분류
- 수학(math)
- 정수론(number_theory)
- 소수 판정(primality_test)
- 에라토스테네스의 체(sieve)
- 다이나믹 프로그래밍(dp)
풀이
웰노운스러운 유형 중 하나이다.
$dp[n]$을 $f(n)$그대로 정의할 때, 소수들을 매개로 진행하는 $knapsack$ $problem$으로 바라볼 수 있다.
$dp[0] = 1$을 기저 사례로 잡고 $n_i$의 구간 내 존재하는 모든 소수들에 대해 냅색$dp$를 돌려주면 되겠다.
보통 물건의 개수가 $1$개임에 따라 현재 시행의 여파를 다음 시행부터 받도록 뒤에서부터 $dp$를 진행한다.
하지만 이번 문제에선 소수들을 중복해서 사용할 수 있으므로, 앞에서부터 진행해도 무방하다.
구간에 대해 $O(n√n)$ 수준의 소수 판정을 해도 범위 상 충분해 보이고, 맘편히 $sieve$를 돌려도 될 듯 하다.
나는 $sieve$를 진행하며 소수가 등장할 때마다 위 $dp$를 진행하였다.
전체 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include<bits/stdc++.h> #define N 100001 std::bitset <N> p; int dp[N]{ 1 }; int main() { for (int i(2); i < N; i++) if (!p[i]) { for (int j(i + i); j < N; j += i) p[j] = 1; for (int j(i); j < N; j++) { dp[j] += dp[j - i]; if (dp[j] > 1000000007) dp[j] -= 1000000007; } } int t; scanf("%d", &t); while (t--) { int n; scanf("%d", &n); printf("%d\n", dp[n]); } } | cs |
comment
끝
'Problem Solving > Baekjoon Online Judge (Gold)' 카테고리의 다른 글
백준 28019 - 산지니의 여행계획 (C++) (0) | 2023.06.28 |
---|---|
백준 28251 - 나도리합 (C++) (0) | 2023.06.26 |
백준 28092 - 우선순위와 쿼리 (C++) (0) | 2023.05.29 |
백준 28131 - K-지폐 (C++) (0) | 2023.05.29 |
백준 28127 - 숫자탑과 쿼리 (C++) (0) | 2023.05.29 |