
t = int(input())
for i in range(t):
n = int(input())
price = list(map(int, input().split()))
m = int(input())
dp = [0] * (m + 1)
dp[0] = 1
for i in price:
for j in range(m + 1):
if j >= i:
dp[j] += dp[j - i]
print(dp[m])
3
2 3 5
10
이럴 경우 정답은 4가 나와야한다.
DP 풀이에 취약하기 때문에 본능적으로 표를 직접 작성하기 시작했다.
처음 2원으로 만들 수 있는 경우의 수를 추출한다.
그 후 2원으로 추출할 수 있는 경우의 수 + 3원으로 추출할 수 있는 경우의 수를 한다.
| i/m | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
| 3 | 1 | 0 | 1 | 1 | 1 | 1 | 2 | 1 | 2 | 2 | 2 |
| 5 | 1 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 4 |

3원의 경우의 수를 확인해보자.
2원의 경우 2원 하나로 대체가 되기 떄문에 count는 그대로 1을 가져온다.
그리고 3의 경우 3원 하나로 가능하기 때문에 0 + 1 해서 1이 된다.
4의 경우 2 + 2만 되기 때문에 그대로 가져오고, 5원은 2 + 3으로 1
6원은 2 + 2 + 2, 3 + 3으로 2개가 된다.
이렇게 += 로 쌓아가는 형식이다.
여기서 이제 규칙을 찾아보자.
for i in price:
for j in range(m + 1):
if j >= i:
dp[j] += dp[j - i]
여기서 다음과 같은 코드가 가능해진다.
DP는 워낙 까다롭고 어렵고, 내가 점화식을 잘 못 찾는 유형이라.. 추후에 연습하려고 했는데 어쩌다보니 도전하게되었다.
많이 어려운 문제는 아니었다고 생각하지만
dp[j] += dp[j - i]에서 dp[j - i] 이 부분을 아마 못 찾았을 것 같다.
점화식을 잘 짜는 것이 정말 중요한 것 같다.
DP는 나중에 연습을 해서 눈이 트이게 되면 상당히 흥미로울 것 같다.