문제
- 문제 링크
BOJ 27519 - 소수의 합
함수 f(n)을 "n을 0개 이상의 소수의 합으로 표현하는 경우의 수" 라고 정의하자.
T개의 n이 주어질 때, 각 n에 맞는 f(n)의 값을 출력해보자.
TL : 3 sec, ML : 128 MB
1≤T≤10,000 0≤ni≤100,000
알고리즘 분류
- 수학(math)
- 정수론(number_theory)
- 소수 판정(primality_test)
- 에라토스테네스의 체(sieve)
- 다이나믹 프로그래밍(dp)
풀이
웰노운스러운 유형 중 하나이다.
dp[n]을 f(n)그대로 정의할 때, 소수들을 매개로 진행하는 knapsack problem으로 바라볼 수 있다.
dp[0]=1을 기저 사례로 잡고 ni의 구간 내 존재하는 모든 소수들에 대해 냅색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 |