알고리즘/Baekjoon
[PS] N포커 / C++ (백준 16565번)
dh_0e
2025. 3. 10. 11:39
조합론의 포함 배제의 원리를 사용하여 포카드가 나올 경우의 수를 구하는 문제
dp[N][K] = N장의 카드를 뽑을 때, K개의 포카드 세트가 나올 수 있는 경우의 수를 저장하는 형식으로 1~N까지 차례로 구하며 dp로 풀 수 있을 것 같아서 5시간 동안 점화식을 찾았다...
결론적으로 이 전의 경우의 수는 관계 X
N개의 카드를 뽑을 때, K개의 포카드 세트가 나왔다고 고정한 뒤, 나올 수 있는 경우의 수를 구한다.
식: $cmp = {_{13}C_K} + {_{(52 - k \times 4)}C_{(N - K \times 4)}}$
K를 1~N/4까지 구해준 다음, 포함 배제의 원리에 의해서 홀수번째는 더해주고, 짝수번째는 빼주면 N개의 카드를 뽑을 때 포카드가 나올 경우의 수를 구할 수 있다.
ex) N이 17일 때
Ans = 포카드 1세트를 고정한 경우의 수 - 포카드 2세트를 고정한 경우의 수 + 포카드 3세트를 고정한 경우의 수 - 포카드 4세트를 고정한 경우의 수
$ = ({_{13}C_1} + {_{48}C_{13}}) - \left( {_{13}C_2} + {_{44}C_9} \right) + \left( {_{13}C_3} + {_{40}C_5} \right) - \left( {_{13}C_4} + {_{36}C_1} \right)$ 가 된다.
#include<iostream>
#include<algorithm>
using namespace std;
long long com[53][53];
long long combination(int n, int r)
{
if (n == r || r == 0)
return 1;
if (com[n][r])return com[n][r];
com[n][r] = (combination(n - 1, r - 1) + combination(n - 1, r)) % 10007;
return com[n][r];
}
int main()
{
int n;
long long ans = 0;
scanf("%d", &n);
for (int i = 1; i <= n/4; i++) {
long long cmp = (combination(13, i) * combination(52 - i * 4, n - i * 4)) % 10007;
if (i % 2 == 1)
ans += cmp;
else ans = ans - cmp + 10007;
ans %= 10007;
}
printf("%lld\n", ans);
return 0;
}