Post

baekjoon 2248:이진수 찾기

baekjoon 2248 이진수 찾기

2248번 이진수 찾기

접근

dp의 2번째 유형이다. k번째 수를 찾으라고 하는 dp이다. 직접 1번째부터 k번째 까지 다 찾게 되면
너무 오래걸리기 때문에 skip을 이용해서 뛰어 넘어서 구한다. 그 뛰어 넘을려면 경우에 맞는 수를 직접
다 나열하는 것이 아닌 dp를 이용해서 바로 개수만 return 하도록 해야한다. 그런 뒤 skip해야하는 수와
비교하여 k번째 수를 결정해 나간다.
여기선 dp(n, l) = n자리 이진수중 1이 l개 이하인 것이다.
dp(n, l) = dp(n-1, l-1) + dp(n-1, l) 이 점화식이다.
skip은 k번째라면 k-1번 skip하는 것으로 해야한다.
dp(n, l)인 상태에서 p번 skip 상태라면 dp(n-1, l)과 비교하여 dp(n-1, l) > p 이면
n자리 수가 0인 경우의 수 안에 p번 skip상태가 있는 것이므로 n자리수에 0을 넣는다.
dp(n-1, l) <= p이면 초과한다는 의미로 n자리수에 1을 넣는다.

코드

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//2248
#include <iostream>
#include <array>
#include <vector>
using namespace std;
array<array<int, 32>, 32> cache;
int dp(int n, int l);
string skip(int n, int l, long long int p);
int main(){
  ios::sync_with_stdio(false);
  cin.tie(0); cout.tie(0);

  int n, l; long long int p;
  cin >> n >> l >> p;
  for(int i = 0; i <= n; i++){
    fill(cache[i].begin(), cache[i].end(), -1);
  }
  cout << skip(n, l, p-1) << '\n';
  //p-1개 건너 뛰고 출력하겠다
  //즉, 0되면 출력임



  return 0;
}
string skip(int n, int l, long long int p){
  // cout << n << ' ' << l << ' ' << p << '\n';
  if(n == 0) {
    // cout << "n=0\n";
    // if(p == 0) cout << "p=0\n";
    return "";
  }
  if(l == 0){
    // cout << "l=0\n";
    // if(p == 0) cout << "p=0\n";
    string s;
    for(int i = 0; i < n; i++){
      s += '0';
    }
    return s;
  }

  if(dp(n-1, l) > p){
    return "0" + skip(n-1, l, p);
  }
  else{

    return "1" + skip(n-1, l-1, p-dp(n-1, l));
  }
}
int dp(int n, int l){
  if(n < l) return dp(n, n);
  if(n == l) return 1 << n;
  if(n == 0 || l == 0) return 1;
  int& ret = cache[n][l];
  if(ret != -1) return ret;
  ret = dp(n-1, l);
  if(l > 0) ret += dp(n-1, l-1);
  return ret;

}

배운 점

dpSkip 문제였다.

This post is licensed under CC BY 4.0 by the author.