https://www.acmicpc.net/problem/1256
1256번: 사전
동호와 규완이는 212호에서 문자열에 대해 공부하고 있다. 김진영 조교는 동호와 규완이에게 특별 과제를 주었다. 특별 과제는 특별한 문자열로 이루어 진 사전을 만드는 것이다. 사전에 수록되
www.acmicpc.net
dp + 조합론 문제였다.
문제를 간단히 정리하자면,
n개의 a와 m개의 z로 구성된 모든 문자열 중 k번째 문자열을 구하는 문제이다.
n과 m의 제한이 100이므로, 모든 모든 조합을 구하는 것은 TLE가 날 것이고 따라서 dp를 이용할 것이다.
k번째 문자열을 구하는 것은 어떻게 할 수 있을까?
처음 상황을 보자.
만약 첫번째 자리에 a를 배치했다고 하면,
남은 총 문자열의 길이는 (n + m - 1)이고, 이 중에 (n - 1)개의 a를 배치하면, 자동으로 m개의 z는 배치가 완료된다.
따라서 (n + m - 1)C(n - 1) 이다.
만약 이 값이 구하려는 k보다 크다면, 해당 위치에 z를 배치하고 작거나 같다면 a를 배치하면 된다.
#include <iostream>
#include <cstring>
using namespace std;
long long dp[201][101];
long long comb(int n, int r) {
if (n == r || r == 0)return 1;
if (dp[n][r] != -1)return dp[n][r];
long long ret1 = 0, ret2 = 0;
ret1 = comb(n - 1, r - 1);
ret2 = comb(n - 1, r);
if (ret1 + ret2 > 1000000000)return dp[n][r] = 1000000001;
else return dp[n][r] = ret1 + ret2;
}
void go(int n, int m, long long k) {
long long c = comb(n + m - 1, n - 1);
if (n > 0 && k <= c) {
cout << 'a';
go(n - 1, m, k);
}
else if (m > 0) {
cout << 'z';
go(n, m - 1, k - c);
}
}
int main() {
int n, m;
long long k;
cin >> n >> m >> k;
memset(dp, -1, sizeof(dp));
if (comb(n + m, n) < k)cout << -1;
else go(n, m, k);
}
'ps' 카테고리의 다른 글
[백준] 11437 - LCA (0) | 2022.08.03 |
---|---|
[백준] 3687 - 성냥개비 (0) | 2022.08.03 |
[백준] 1562 - 계단수 (0) | 2022.08.03 |
[백준] 2610 - 회의준비 (0) | 2022.08.01 |
[백준] 17136 - 색종이 붙이기 (0) | 2022.07.27 |
댓글