[BOJ] 16566: 카드 게임 (C/C++)
문제 16566번: 카드 게임
철수와 민수는 카드 게임을 즐겨한다. 이 카드 게임의 규칙은 다음과 같다.
- N개의 빨간색 카드가 있다. 각각의 카드는 순서대로 1부터 N까지 번호가 매겨져 있다. 이 중에서 M개의 카드를 고른다.
- N개의 파란색 카드가 있다. 각각의 카드는 순서대로 1부터 N까지 번호가 매겨져 있다. 이 중에서 빨간색에서 고른 번호와 같은 파란색 카드 M개를 고른다.
- 철수는 빨간색 카드를 가지고 민수는 파란색 카드를 가진다.
- 철수와 민수는 고른 카드 중에 1장을 뒤집어진 상태로 낸다. 그리고 카드를 다시 뒤집어서 번호가 큰 사람이 이긴다. 이 동작을 K번 해서 더 많이 이긴 사람이 최종적으로 승리한다. 한 번 낸 카드는 반드시 버려야 한다. 철수는 뛰어난 마술사이기 때문에 본인이 낼 카드를 마음대로 조작할 수 있다. 즉, 카드를 버리고 민수 몰래 다시 들고 온다거나 민수한테 없는 카드를 내기도 한다.
민수는 뛰어난 심리학자이기 때문에 철수가 낼 카드를 알아낼 수 있다. 그래서 민수는 철수가 낼 카드보다 큰 카드가 있다면 그 카드들 중 가장 작은 카드를 내기로 했다.
K번 동안 철수가 낼 카드가 입력으로 주어진다. 그렇다면 민수가 어떤 카드를 낼지 출력하라. 단, 민수가 카드를 내지 못하는 경우는 없다고 가정한다.
입력
첫째 줄에 세 개의 자연수 N, M, K가 주어진다. (1 ≤ M ≤ N ≤ 4,000,000, 1 ≤ K ≤ min(M, 10,000))
다음 줄에 카드의 번호를 나타내는 M개의 자연수가 주어진다. 각각의 수들은 1 이상이고 N 이하이며 서로 다르다.
다음 줄에 K개의 자연수가 주어진다. i번째 수는 철수가 i번째로 내는 카드의 번호이다. 철수가 내는 카드 역시 1 이상 N 이하이다.
출력
K줄에 걸쳐서 수를 출력한다. i번째 줄에는 민수가 i번째로 낼 카드의 번호가 출력되어야 한다.
문제분석
문제 요구사항
- 철수가 낼 카드보다 큰 카드중 가장 작은 카드를 내야함 -> Binary search로 탐색
- 조건을 만족하는 카드가 이미 제출하여 없는 경우가 존재 할 수 있음 -> 존재 하지 않는 카드의 index를 Set을 이용하여 제외시킴
Binary search와 Disjoint Set를 이용하여 풀이 할 수 있음.
구현
먼저 std::upper_bound를 이용하여 Binary search를 통해 해당 카드의 index를 알아냄, 그 후 각각의 카드에 대하여 valid한 index를 저장하는 indexes를 활용하여 GetIndex함수를 이용하여 valid한 카드의 index를 return함.
증명
먼저 std::upper_bound를 통하여 query로 들어온 값보다 큰 수중 가장 작은 값을 찾는다. 그 후, GetIndex를 통하여 valid한 카드의 index를 return한다.
그 후,MergeIndex를 통하여 l_index를 r_index의 set에 Merge 시키는데, MergeIndex를 통하여 GetIndex(l_index)가 가르키고 있는 카드를 없애면서, 그 다음에 valid한 카드의 index를 참조하는 효과가 생기기에 유효한 코드이다.
코드
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
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::vector<int> indexes;
const int GetIndex(const int index) {
return indexes[index] == index ? index
: indexes[index] = GetIndex(indexes[index]);
}
void MergeIndex(const int l_index, const int r_index) {
if (r_index < indexes.size()) {
indexes[GetIndex(l_index)] = GetIndex(r_index);
}
return;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr), std::cout.tie(nullptr);
int N, M, K;
std::cin >> N >> M >> K;
std::vector<bool> valid_num(N + 1);
int num;
for (int i = 0; i < M; ++i) {
std::cin >> num;
valid_num[num] = true;
}
std::vector<int> v;
v.reserve(M);
for (int i = 0; i < valid_num.size() && v.size() < M; ++i) {
if (valid_num[i]) {
v.push_back(i);
}
}
indexes.assign(v.size(), 0);
for (int i = 0; i < indexes.size(); ++i) {
indexes[i] = i;
}
int query;
for (int i = 0; i < K; ++i) {
std::cin >> query;
const int index =
GetIndex(std::upper_bound(v.begin(), v.end(), query) - v.begin());
std::cout << v[index] << "\n";
MergeIndex(index, index + 1);
}
return 0;
}