포스트

[BOJ] 16566: 카드 게임 (C/C++)

[BOJ] 16566: 카드 게임 (C/C++)

문제 16566번: 카드 게임

철수와 민수는 카드 게임을 즐겨한다. 이 카드 게임의 규칙은 다음과 같다.

  1. N개의 빨간색 카드가 있다. 각각의 카드는 순서대로 1부터 N까지 번호가 매겨져 있다. 이 중에서 M개의 카드를 고른다.
  2. N개의 파란색 카드가 있다. 각각의 카드는 순서대로 1부터 N까지 번호가 매겨져 있다. 이 중에서 빨간색에서 고른 번호와 같은 파란색 카드 M개를 고른다.
  3. 철수는 빨간색 카드를 가지고 민수는 파란색 카드를 가진다.
  4. 철수와 민수는 고른 카드 중에 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;
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.