문제 링크: https://www.acmicpc.net/problem/15989
다이나믹 프로그래밍 문제입니다. bottom-up 방식으로 풀어봤습니다.
일단 문제에 없는 조건 '오름차순으로만 더할 수 있다'를 추가해봅니다. 왜냐면 그렇게 해야 중복으로 세는 경우를 뺄 수 있거든요.
그리고 dp 식을 적어보면 아래와 같습니다.
\[ dp[i][j] = \text{정수 i를 만들 때 마지막으로 더한 수가 j인 경우의 수} \]
더할 수 있는 1, 2, 3이니까 경우의 수를 아래처럼 나눌 수 있습니다.
- 마지막에 더한 수가 1인 경우: 바로 앞에 더한 수는 1밖에 나올 수 없습니다
- 마지막에 더한 수가 2인 경우: 바로 앞에 더한 수가 1, 2가 나올 수 있습니다
- 마지막에 더한 수가 3인 경우: 바로 앞에 더한 수가 1, 2, 3이 나올 수 있습니다
이걸 식으로 정리하면
\begin{align}
dp[i][1] &= dp[i-1][1] \\
dp[i][2] &= dp[i-2][1]+dp[i-2][2] \\
dp[i][3] &= dp[i-3][1]+dp[i-3][2]+dp[i-3][3]
\end{align}
인 걸 알 수 있습니다.
#pragma GCC optimize ("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,avx,avx2")
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
long long dp[10001][3];
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n;
cin >> n;
dp[0][0] = 1;
for (int i = 1; i <= 10000; ++i) {
dp[i][0] = dp[i - 1][0];
if (i > 1)
dp[i][1] = dp[i - 2][0] + dp[i - 2][1];
if (i > 2)
dp[i][2] = dp[i - 3][0] + dp[i - 3][1] + dp[i - 3][2];
}
while (n--) {
int in;
cin >> in;
cout << accumulate(dp[in], dp[in] + 3, 0LL) << '\n';
}
return 0;
}
bottom-up 방식으로 구현한 코드입니다.
위에 쓴 식과 다른 점이 dp[i][j]에서 j 부분이 0, 1, 2인데 그냥 다음부터는 [4]로 선언해서 [1, 2, 3] 이런식으로 써야겠습니다. 헷갈리네요. 메모리 좀 더 쓴다고 죽는 것도 아니니까요
반응형
'Online Judge > 백준' 카테고리의 다른 글
[백준][C++] 1717: 집합의 표현 (0) | 2020.05.22 |
---|---|
[백준][C++] 1247: 부호 (0) | 2020.05.20 |
[백준][C++] 10539: 수빈이와 수열 (0) | 2020.05.18 |
[백준][C++] 3954: Brainf**k 인터프리터 (0) | 2020.05.14 |
[백준][C++] 17414: Sebin Loves Euler Circuit (0) | 2020.05.14 |