https://www.acmicpc.net/problem/11051
11051번: 이항 계수 2
첫째 줄에 \(N\)과 \(K\)가 주어진다. (1 ≤ \(N\) ≤ 1,000, 0 ≤ \(K\) ≤ \(N\))
www.acmicpc.net
아이디어는 nCk = n/k * (n-1)C(k-1) 임을 이용하는 점화식이다. k가 1인 경우 nCk는 n, k가 0이면 1인 것도 인지하자.
처음 짠 코드는 다음과 같다. 배열을 처음에는 dp[1001][1001]로 했는데 실행이 안되서, nCk=nC(n-k)임을 이용했다.
#include <cstdio>
int main(void){
int N, K;
scanf("%d %d",&N ,&K);
if(K>N/2) K=N-K;
int dp[1001][501]={};
for(int i=1; i<=N; i++){
for(int j=0; j<=i; j++){
if(j==0) dp[i][j]=1;
else if(j==1) dp[i][j]=i;
else if(i==j) dp[i][j]=1;
else dp[i][j]=(int)((double)i/j*dp[i-1][j-1]);
}
}
printf("%d",(int)dp[N][K]);
}
그리고 런타임에러. 생각해보니, 모든 dp를 구할 필요가 없다. 그래서 일차원 dp(해당 경우의 dp만..? 따지는)를 설정해 다시 해보았는데,
#include <cstdio>
int main(void){
int N, K;
scanf("%d %d",&N ,&K);
if(K>N/2) K=N-K;
long long int dp[1001]={0,N-K+1,};
int cnt1=N-K+1;
for(int i=2; i<=K; i++){
cnt1++;
dp[i]=(cnt1*dp[i-1])/i;
}
if(K==0) printf("1");
else printf("%lld",dp[K]%10007);
}
곱셈이라 10007로 나누어야 한다는 조건을 만족시키기 까다롭다.
사실 이항 계수를 구하는 식은 하나 더 있다. nCk = n-1Ck-1 + n-1Ck 인데, 이 식을 이용하면
#include <cstdio>
int main(void){
int N, K;
scanf("%d %d",&N ,&K);
if(K>N/2) K=N-K;
int dp[1001][501];
for(int i=1; i<=N; i++){
for(int j=0; j<=K && j<=i; j++){
if(j==0) dp[i][j]=1;
else if(j==i) dp[i][j]=1;
else dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
dp[i][j] = dp[i][j] % 10007;
}
}
printf("%d",dp[N][K]);
}
이항 계수의 성질을 잘 알면 쉽게 풀 수 있지만, 모른다면 까다로워 보인다. 문제를 풀기 전에 성질을 알고 들어가자.
'알고리즘 문제' 카테고리의 다른 글
[C/C++ 백준 9251번] LCS (Gold 5) (0) | 2020.05.17 |
---|---|
[C/C++ 백준 10164번] 격자상의 경로 (Silver 1) (0) | 2020.05.16 |
[C/C++ 백준 11057번] 오르막 수 (Silver 1) (0) | 2020.05.16 |
[C/C++ 백준 9465번] 스티커 (Silver 2) (0) | 2020.05.15 |
[C/C++ 백준 9507번] Generations of Tribbles (Silver 3) (0) | 2020.05.15 |