Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cpp] 7차 Softeer 정기 역량 진단 1번 문제 - 자동차 테스트 #63

Merged
merged 4 commits into from
Sep 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions seoul_21_minjaekim/Softeer/HSAT_7th/1/HSAT_7th_1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;

int main(int argc, char** argv)
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);

int n, q;
cin >> n >> q;

int cars[50000];
for (int i = 0; i < n; ++i)
cin >> cars[i];

sort(cars, cars + n);

unordered_map<int, int> map;
for (int i = 0; i < n; ++i)
map[cars[i]] = i + 1;
minjae9610 marked this conversation as resolved.
Show resolved Hide resolved

for (int i = 0; i < q; ++i) {
int m, m_idx;
cin >> m;
m_idx = map[m];
cout << (m_idx ? (m_idx - 1) * (n - m_idx) : m_idx) << '\n';
minjae9610 marked this conversation as resolved.
Show resolved Hide resolved
}

return 0;
}
89 changes: 89 additions & 0 deletions seoul_21_minjaekim/Softeer/HSAT_7th/1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# [7차 Softeer 정기 역량 진단] 1번 - 자동차 테스트

## 카테고리

자료구조, 해시 테이블

## 시간복잡도

`O(N * log N + Q)`

## 문제

자동차의 연비들을 제공해준다.

자동차 중 임의의 3개를 골랐을 때, 중앙값이 `m`이 될 수 있는 서로 다른 경우의 수를 구하라.

n대의 자동차에 대한 연비의 정보와 `q`개의 `m`값이 주어진다.

## 제약 조건

- 1 ≤ n ≤ 50,000
- 1 ≤ q ≤ 200,000
- 1 ≤ 연비 ≤ 1,000,000,000
- 1 ≤ m ≤ 1,000,000,000
- 각 차량의 연비는 모두 다르다.

## 시간 제약

- Java : 3초
- C++ : 2초
- Python : 2초

## 입력 형식

- 첫 번째 줄에 `n`, `q`가 주어진다.
- 두 번째 줄에 `n`개의 자동차의 연비에 해당하는 값이 공백을 사이에 두고 주어진다.
- 세 번째 줄부터 `q`개의 줄에 걸쳐 각 줄에 `m`값이 주어진다.

## 출력 형식

`q`개의 줄에 걸쳐 각 줄에 `m`값이 중앙값이 될 수 있는 서로 다른 경우의 수를 출력한다.

## 해설

데이터를 입력받는다. `O(N)`

```cpp
int n, q;
cin >> n >> q;

int cars[50000];
for (int i = 0; i < n; ++i)
cin >> cars[i];
```

입력받은 데이터를 정렬한다. `O(N * log N)`

```cpp
sort(cars, cars + n);
```

정렬된 데이터를 키로, 인덱스를 값으로 하는 해시 테이블을 만든다. 이때 해시 테이블에 없는 값을 조회했을때 나오는 리턴값인 `0`과 구분을 위해 인덱스에 `1`을 더해서 저장한다. `O(N)`

```cpp
unordered_map<int, int> map;
for (int i = 0; i < n; ++i)
map[cars[i]] = i + 1;
```

`q`개의 `m`값을 입력받아 해시 테이블에서 조회한다. 3개의 값을 뽑았을 때, `m`이 중간값이 되는 경우는 `m`의 왼쪽에서 한 개, `m`의 오른쪽에서 한 개를 뽑는 경우의 수와 같다. 이는 `m`의 왼쪽 개수 * `m`의 오른쪽 개수로 상수시간으로 계산이 가능하다. `O(Q)`

```cpp
for (int i = 0; i < q; ++i) {
int m, m_idx;
cin >> m;
m_idx = map[m];
cout << (m_idx ? (m_idx - 1) * (n - m_idx) : m_idx) << '\n';
}
```

## 문제 분석

문제의 제약조건에서 알 수 있다싶이, `n`의 최대값이 `50,000`이고 `q`의 최대값이 `200,000`이다. `n`이 `50,000`이고 `q`가 `200,000`이라면, `n`개의 자동차 중 임의의 3개를 직접 골라서, 중앙값이 `m`이 될 수 있는 서로 다른 경우의 수를 구하는 것은 `O(N^3)`의 시간복잡도를 가진다. 제한시간인 `2초`를 넘어가기 때문에, `O(N^3)`의 알고리즘으로는 풀 수 없다.

이는 최소한 `O(Q * log N)`의 알고리즘으로 풀어야 한다는 것을 의미한다.

`O(Q * log N)`의 알고리즘으로 풀기 위해서는, `n`개의 자동차의 연비를 정렬한 다음 각 `q`에 대해 `m`의 인덱스를 이진 탐색으로 찾아야 한다.

본 풀이와 같이 해시 테이블을 이용한 `O(N * log N + Q)` 알고리즘으로도 풀 수 있다.