728x90
728x90
Step 1.
n자리의 이진수에서 비트 r개를 쓰는 경우의 수는 $\binom{n}{r}$이 된다.
이항 계수를 구현하고 누적합을 통해 n자리에서 r개 비트 이하를 쓰는 경우의 수도 구해주자.
0으로 시작하는 이진수도 인정됨에 유의한다. 즉 0이 첫번째 이진수가 되겠다.
n자리까지 n을 초과한 비트의 갯수만큼 사용하는 경우의 수는 n개의 비트를 사용한 것으로 간주하여 누적합에 반영해주자.
Step 2.
이항 계수의 누적합을 구하면 n부터 1까지 반복문을 돌려주자.
$idx$번째 자리와 $l$개의 비트가 남아있을 때
이항 계수의 누적합 := prefixsum[idx][l]
남은 자릿수 := i라고 하자.
prefixsum[idx - 1][l] < i 이면 $idx - 1$번째까지 비트 $l$개를 쓴 경우보다 뒤에 있는 수가 되므로 $idx$번째는 1로 채울 수 있다. 1을 출력해주자. 비트를 한 개 사용한 것이므로 $l$도 하나 빼주는 것을 잊지 말자
비트를 모두 소진하거나 위 조건을 만족하지 않을 때 0을 출력하면 정답이 된다.
전체 코드
더보기
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
|
#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <algorithm>
#include <numeric>
using namespace std;
using ll = long long;
int n, l;
ll ith;
ll dp[32][32];
ll prefixbino[32][32];
ll bino(int n, int r)
{
if (n < r || n < 0 || r < 0)
return 0;
ll &ret = dp[n][r];
if (ret != -1)
return ret;
return ret = bino(n - 1, r) + bino(n - 1, r - 1);
}
int main()
{
memset(dp, -1, sizeof dp);
dp[0][0] = dp[1][0] = dp[1][1] = 1;
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> l >> ith;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= 31; ++j)
for (int k = 0; k <= j; ++k)
prefixbino[i][j] += bino(i, k);
for (int i = n; i >= 1; --i)
{
if (!l)
{
cout << 0;
continue;
}
if (prefixbino[i - 1][l] < ith)
{
cout << 1;
ith -= prefixbino[i - 1][l--];
}
else
cout << 0;
}
}
|
cs |
728x90
728x90
'백준 > DP' 카테고리의 다른 글
백준 11051 - 이항 계수 2 (0) | 2020.11.30 |
---|---|
[ICPC] 백준 4811 - 알약 (0) | 2020.11.30 |
백준 1328 - 고층 빌딩 (0) | 2020.11.15 |
[KOI] 백준 1983 - 숫자 박스 (0) | 2020.11.15 |
백준 2176 - 합리적인 이동경로 (0) | 2020.11.14 |