이전 포스트
solved.ac class 7++ 도전기 1
solved.ac class 7++ 도전기 2
solved.ac class 7++ 도전기 3
오랜만에 class 7++ 등반으로 찾아왔습니다! 오늘 포스팅할 문제들은 사실 이미 거의 한달 전에 푼 것들인데 이제야 올리네요. 블로그주인 일해라 ICPC 예선 전후로 좀 정신없었어서 클래스 7++등반에 신경을 못 썼었는데 이제 다시 등반을 시작해볼까 합니다.
클래스 7 문제 5개를 120분 안에 푸는 것을 목표로 했으며, 문제 목록은 다음과 같습니다.
A. BOJ 3640 - 제독
B. BOJ 10266 - 시계 사진들
C. BOJ 10277 - JuQueen
D. BOJ 14572 - 스터디 그룹
E. BOJ 16404 - 주식회사 승범이네
A. BOJ 3640 - 제독 (Solved at 13 min)
티어: 플래티넘 II
그래프 모델링은 solved.ac class 7++ 도전기 3에서 설명한 ‘도시 왕복하기 2’ 문제와 동일합니다. 다만 디테일한 부분에서 다음과 같은 사소한 차이가 있습니다.
- 목적지가 고정되어있지 않다. (도시 왕복하기 2에서는 2번 정점으로 고정)
- 출발지와 도착지에서의 초록 간선의 유량은 2이다. (도시 왕복하기 2에서는 inf)
- 몇 번 왕복할 수 있는지를 계산하는 도시 왕복하기 2와 다르게, 이 문제에서는 두 전함이 목적지까지 딱 한번만 가기 때문입니다.
- 간선에 cost가 존재한다.
- 이로 인해 이 문제에서는 단순 flow가 아닌 MCMF를 사용해야 합니다.
코드
1 |
|
D. BOJ 14572 - 스터디 그룹 (Solved at 59 min)
티어: 플래티넘 V
그룹원이 늘어날수록 그룹원 수와 그룹 내의 학생들이 아는 모든 알고리즘의 수는 증가하는 반면, 그룹 내의 모든 학생들이 아는 알고리즘 수는 감소합니다. 즉, 그룹원이 늘어날수록, 효율성 \( E \)는 좋아지기만 한다는 것을 알 수 있고, 이는 그리디 알고리즘을 사용하기 적절한 상황입니다.
하지만 그룹 내에서 가장 잘 하는 학생과 가장 못하는 학생의 실력차가 \( D \) 이하여야 한다는 조건 때문에, 모든 학생을 다 그룹원으로 받아들일 순 없습니다. 대신 이 조건을 추가해도 그룹원이 늘어날수록 효율성이 좋아진다는 성질은 여전하기 때문에, 각 학생의 실력 \( d_i \)에 대해 실력이 \( d_i \)이상 \( d_i+D \)이하인 학생을 모두 그룹원으로 받아들였을 때의 효율성을 구하고, 이중 최댓값을 취하면 됩니다.
물론 효율성을 그냥 구하면 시간복잡도가 \( O(N^2) \)이 돼서 터지기 때문에, 학생들을 \( d_i \)에 대한 오름차순으로 정렬한 후, 투 포인터를 사용하면 \( O(N \log N+KN) \)에 문제를 해결할 수 있습니다. 이때 \( K \)가 붙은 이유는 각 구간에 대해, 그룹 내에 모든 학생들이 알고 있는 알고리즘 수는 \( O(K) \)에 일일히 구할수밖에 없기 때문입니다.
코드
1 |
|
E. BOJ 16404 - 주식회사 승범이네 (Solved at 98 min)
티어: 플래티넘 III
우선 판매원을 정점, 사수-부사수 관계를 간선으로 보고, 사수 정점을 부사수 정점의 부모 정점으로 나타냈을 때, 1번 정점이 루트인 트리를 형성함을 알 수 있습니다. 그리고 1번 쿼리가 수행됐을 때, \( i \)번 직원이 \( w \)만큼 이익/손해를 봤을때, ‘subtree’(부사수)에 속하는 정점들도 똑같이 \( w \)만큼 이익/손해를 보는 형태인데, 이는 오일러 경로 테크닉을 사용하기 좋은 형태입니다.
오일러 경로 테크닉을 사용하면 1번 쿼리를 세그먼트 트리의 구간 쿼리로, 2번 쿼리를 점 쿼리로 변환할 수 있고, 이는 레이지 세그를 사용하여 풀 수 있습니다. 레이지 안 쓰는 풀이도 있는데 이건 나중에 추가하도록 하겠습니다.
코드
1 |
|
C. BOJ 10277 - JuQueen (Solved at 118 min)
티어: 플래티넘 II
평범한 구간 쿼리 세그문제인데, groupchange 쿼리나 change 쿼리 수행도중 어떤 core의 frequency값이 0 미만이나 \( N \) 초과가 되면 즉시 해당 쿼리를 중단한다는 점이 유일한 차이입니다.
해결 방법은 간단합니다. groupchange/change 쿼리를 하기에 앞서, \( S \)값(change 쿼리의 경우 \( X \)값)이 양수이면 구간 내에서 가장 큰 값, 음수이면 구간 내에서 가장 작은 값을 찾습니다. \( S \)이 음수든 양수든 로직은 동일하기 때문에 양수라고 가정하고, 이때 구간 내의 최댓값을 \( M \)이라고 하겠습니다. \( M+S \le N\)이라면 주어진 구간에 S를 그대로 더하고, \( M+S > N \)이라면 주어진 구간에 \( N-M \)을 더하면 됩니다.
구간 쿼리니까 레이지 세그를 사용하셔도 되고, 위의 ‘주식회사 승범이네’ 문제와 마찬가지로 레이지 없이 푸는 방법도 있습니다.
코드
1 |
|
B. BOJ 10266 - 시계 사진들 (WA 1회, TLE 1회)
티어: 플래티넘 V
우선 시계 바늘의 각도가 0 이상 359,999 이하의 정수로 정의되기 때문에, 우리는 두 시계 사진을 길이 360,000의 문자열로 나타낼 수 있습니다. 이때 각도가 \( i \)인 시계 바늘이 존재한다면 문자열의 \( i \)번 인덱스는 1, 아니라면 0입니다. 이렇게 시계를 문자열로 변환하고 나면, 두 문자열이 아래 사진과 같이 매칭되는지를 확인하면 됩니다.
우선 1번 시계를 나타내는 문자열을 문자열 \( A \)(위), 2번 시계를 나타내는 문자열을 문자열 \( B \)(아래)라고 하겠습니다. 이때 위 사진에서 생략된 정의는 다음과 같습니다.
- 문자열 \( A \)의 suffix가 문자열 \( B \)의 prefix가 길이 \( d_1 \)만큼 일치한다. (위 사진의 빨간색 영역)
- 문자열 \( A \)의 prefix가 문자열 \( B \)의 suffix가 길이 \( d_2 \)만큼 일치한다. (위 사진의 파란색 영역)
- \( d_1+d_2 = N \)(문자열의 길이)이다.
여기서 \( d_1 \)은 KMP를 돌리면 찾을 수 있고, 문자열 \( B \)의 \( d_1 \)번째 인덱스부터 \( N-1 \)번째 인덱스가 문자열 \( A \)의 \( 0 \)번째 인덱스부터 \( N-d_1-1 \)번째 인덱스까지 일치하는지 확인하면 2번, 3번조건도 확인할 수 있습니다.
코드
1 |
|
이제 class 7++까지 4문제 남았는데.. 여태까지는 class 7 문제들 중 풀이가 떠오른 문제들을 골라서 시간 재고 풀었는데, 남은 문제들은 거의 다 충분히 생각해도 풀이가 안 떠오르는 문제들이다 보니 이 문제들은 따로 시간을 재고 풀지는 않을 것 같네요. 빠른 시일내에 class 7++ 등반을 끝내고 class 8++ 등반으로 찾아뵙겠습니다!