요즘 컨디션이 좋다. 실력이 늘은건지 웰노운이 나온건지 잘 모르겠지만 암튼 계속 올라서 좋긴 하다.
A. Balanced Substring
a의 개수와 b의 개수가 같은 substring을 찾는 문제이다. 문자열 "ab" 또는 "ba"는 항상 조건에 맞기 때문에, 그냥 주어진 문자열에서 "ab" 또는 "ba"가 있는지만 판별하면 된다.
놀랍게도 완탐을 돌리다 TLE 맞고 틀렸다. n이 작길래 무지성으로 냈는데 다시 찬찬히 계산해보니 1e9가 넘더라
B. Chess Tournament
참여자들을 정점으로 하는 그래프로 모델링하면 완전 그래프가 만들어진다. 1번 타입의 참가자는 절대 지면 안된다. 따라서 1번 타입 참가자에 연결된 간선들을 모두 지운다. 이제 남은 간선들을 가지고 2번 타입 참가자들을 연결해보자. 2번 타입 참가자들은 최소 1번만 이기면 된다. 즉, outdegree가 1 이상이 되도록 만들어야 한다. 완전 그래프기 때문에, 항상 2번 타입 참가자들을 잇는 단순 사이클이 만들어 질 수 있다. 아래 그림은 세 번째 테스트케이스의 풀이이다.
단순 사이클이 만들어지지 않는 경우는, 2번 타입 참가자가 2명 이하인 경우이다. 한편 2번 타입 참가자가 0명이라면 모든 참가자들이 서로 비기기만 하면 된다.(첫 번째 테스트케이스) 따라서 2번 타입 참가자가 1명이나 2명인 경우만 NO이고 나머지 모든 경우는 YES이다. YES라면, 앞에서 설명한 대로 단순 사이클을 만들고 그 사이클에 포함되는 간선을 제외한 모든 간선을 비기는 경우로 지정하면 된다.
C. Jury Meeting
nice하지 않은 경우를 생각해보자. 문제에 제시된 예시들을 잘 관찰해보면 다음과 같은 규칙을 찾을 수 있다.
수열 $a$에서 가장 큰 원소를 $a_k$라고 하자. $a_k$와 값이 같은 원소가 더 있다면, 항상 nice하다.
값이 $a_k - 1$인 원소가 하나도 없다면 항상 nice하지 않다.
$a_k$ 이후에 값이 $a_k - 1$인 원소가 하나도 없다면 항상 nice하지 않다. 즉, $p$에 따라 $a$를 재배열했을 때, 구간 (k, n] 안의 모든 $i$에 대하여 $a_i < a_k - 1$이면 항상 nice하지 않다.
첫 번째 경우는 항상 nice하므로 $n!$이 답이다. 두 번째 경우는 항상 nice하지 않으므로 0이 답이다. 세 번째 경우를 잘 계산해야 하는데, 값이 $a_k - 2$보다 작은 원소가 $l$개라고 하면 다음과 같이 계산할 수 있다. $$ n! - \sum_{i=0}^l (n-i-1)! {k \choose i} i! $$ 팩토리얼은 오프라인으로 미리 계산해 둘 수 있고, combination은 페르마의 소정리와 분할정복을 통해 O(log n)에 계산할 수 있다.
역시 조합론 문제는 어렵다. 예제가 굉장히 잘 나와있어서 겨우 규칙을 관찰해 낼 수 있었다.
D. Inconvenient Pairs
불편한 쌍이 만들어지는 조건은 다음과 같다.
교차로 위에 있는 사람은 항상 불편한 쌍을 만들 수 없다.
같은 열에 있는 가로 도로에 있으면서 서로 다른 도로에 있는 두 사람은 항상 불편한 쌍이다.
같은 행에 있는 세로 도로에 있으면서 서로 다른 도로에 있는 두 사람은 항상 불편한 쌍이다.
먼저, 세로 도로와 사람들을 x좌표에 대하여 정렬한다. 이를 스위핑하면 같은 열에 있는 사람들을 골라낼 수 있다. 예를 들어 두 번째 테스트 케이스에서 1, 6, 7번 사람이 한 그룹, 8번 사람이 다른 한 그룹으로 분류된다. 이 골라낸 그룹을 이번엔 y좌표로 정렬한다. 그러면 한 그룹 내에서 같은 가로 도로에 있는 사람의 수를 찾아낼 수 있다. 현재 그룹의 크기를 $n$이고 같은 도로에 있는 사람이 $k$명이면 $\frac{\sum k(n-k)}{2}$이 불편한 쌍의 개수다.
역대급 퍼포먼스다. 원래 carrot은 잘라내고 캡쳐해오는데 오늘은 좀 자랑하고 싶어서 다 나오게 찍었다.
A. Domino Disaster
입력된 문자열의 각 문자에 따라 출력할 문자가 1대1로 대응된다. U이면 D, L이면 L, R이면 R로 대응해서 출력하면 된다.
B. MEXor Mixup
MEX 결과가 a라는 것은, [0, a) 범위의 모든 정수가 이미 수열 내에 존재한다는 뜻이다. 오프라인으로 일단 0~3e5 까지 xor한 결과를 저장해 둔다. a-1까지 xor한 결과를 가지고 b와 비교해볼 수 있다. 만약 $xored[a-1] = b$라면 a가 답이다. $xored[a-1] \ne b$ 라면 $xored[a-1] \oplus b$을 추가하면 b가 나오기 때문에 a+1이 답이다. 그런데 $xored[a-1] \oplus b$가 a와 같을 수 있다. 그렇다면 임의의 x에 대하여 $xored[a-1] \oplus b \oplus x$와 $x$를 수열에 추가하면 된다. 이 때 답은 a+2이다.
C. Carrying Conundrum
brute force로 해결될 수도 있을 것 같은데, 그냥 무지성 경우의 수 DP를 사용했다.
$dp[i][bit] = (i\text{번째 자리까지 덧셈을 했을때, 자리올림이 }bit)$으로 정의한다. 자리 올림을 2bit로 들고 다니면서 관리해주고, 1의 자리부터 1e9의 자리까지 처리해주면 된다. 이 때, (0, n), (n, 0)인 순서쌍도 세지므로 dp 결과에 -2를 하면 답이다.
E. Non-Decreasing Dilemma
아주 전형적인 세그먼트 트리 문제이다. 흔히 알려진 테크닉인 금광세그를 풀어봤다면 쉽게 풀이를 떠올렸을 것이다.
세그먼트 트리의 노드를 다음과 같은 6개의 원소를 가진 struct로 정의하자.
ans : 이 구간에서 단조증가하는 subarray의 개수. 즉, 구간쿼리의 답
sz : 이 구간의 길이
lval : 이 구간의 왼쪽 끝 원소의 값
lsz : 이 구간의 왼쪽 끝 원소를 포함하는 subarray의 길이
rval : 이 구간의 오른쪽 끝 원소의 값
rsz : 이 구간의 오른쪽 끝 원소를 포함하는 subarray의 길이
일단 트리의 leaf에서는 ans = 1이고, lval = rval, sz = lsz = rsz이다.
두 서브노드 left와 right가 합쳐질 때 위 그림과 같이 두 가지 경우가 존재할 수 있다. 그림에서 초록색 박스는 left 노드, 파란색 박스는 right 노드이다. 노란색은 각 노드가 커버하는 구간에서 subarray이다.
첫 번째로 $left.rval > right.lval$인 경우이다.(빨강색 박스) 이 때, left의 오른쪽 끝 subarray(노란색 r) 과 right의 왼쪽 끝 subarray(노란색 l)은 그대로 나열된다. 따라서, $ret.ans = left.ans + right.ans$이다.
두 번째로 $left.rval \leq right.lval$인 경우이다.(하늘색 박스) 이 때, left의 오른쪽 끝 subarray(노란색 r) 과 right의 왼쪽 끝 subarray(노란색 l)은 merge된다. 즉, 이전에 존재했던 두 subarray를 제외하고, 새로 생긴 subarray(노란색 r+l)을 계산해야 한다. 따라서, $ret.ans = left.ans + right.ans - \frac{left.rsz(left.rsz+1)}{2} - \frac{right.lsz(right.lsz+1)}{2} + \frac{(left.rsz+right.lsz)(left.rsz+right.lsz+1)}{2}$이다.
단, 여기서 주의해야 할 것은, 서브노드 전체가 하나의 subarray로 존재하는 경우에는 ret.lsz 또는 ret.rsz를 다시 계산해야 한다. 예를 들어 위 그림처럼 $left.lsz = left.sz$인 경우, ret.lsz는 left.lsz가 아니라 left.sz + right.lsz이다. 마찬가지로 $right.lsz = right.sz$인 경우, $ret.rsz = left.rsz + right.sz$이다.
이러한 방식으로 두 서브노드를 합칠 수 있다. 세그먼트 트리를 정의했다면 나머지는 각 쿼리에 맞게 트리에 update 또는 query를 하면 된다.
5등까지 상품이 나가는데, 시작하고서 가벼운 마음으로 대충 문제 훑어보다가 5~10분 정도 날렸다. 만약에 바로 A번 잡고 풀었다면 3솔도 할 수 있었는데 아쉬웠다.
A. permutation making (00:14)
최대한 누적합이 같게 만들어줘야 한다. 누적합을 N으로 나머지 연산을 하므로, N의 배수들은 모두 똑같이 0으로 취급된다. 따라서 누적합이 N의 배수가 나오도록 N, 1, N-1, 2, N-2, ... 이렇게 배치해주면 된다. 그러면 홀수 번째 원소들은 모두 같고, 짝수 번째 원소들은 다 다르므로 조건을 만족한다.
D. 신촌 수열과 쿼리 (01:16)
2번 쿼리를 살펴보면, 구간 [l, i]에서 모든 원소가 j 이상이 되도록 l을 최대한 감소시키고, 구간 [i, r]에서 모든 원소가 j 이상이 되도록 r을 최대한 증가시키면 된다. 최솟값 세그트리를 사용해서 구간 [l, i] 또는 구간 [i, r]에 j보다 작은 원소가 있는지 O(logN) 안에 찾을 수 있다. 이분 탐색을 한 번씩 사용해서 조건을 만족하는 동안 l의 최솟값 그리고 r의 최댓값을 각각 구할 수 있다. 이렇게 하여 O(log log N) 안에 2번 쿼리를 해결할 수 있다.
1번 쿼리는 그냥 세그트리에 update해주면 된다.
문제를 잘못 읽어서 굉장히 헤멨다. 2번 쿼리의 구간에 i가 포함되어야 한다는 조건을 놓쳐서 머지소트트리+금광세그를 짜야 하나 고민했다.
G. 신촌방위본부 (업솔빙)
나무가 불에 타는 조건은, 내분점 공식과 동일하다. 즉, 미사일이 떨어진 좌표를 이어서 만든 도형의 내부(모서리에 걸친 점도 포함)에 있는 모든 나무가 불에 탄다는 뜻이다. 미사일이 떨어진 좌표들의 볼록껍질을 구하고 볼록다각형의 넓이를 구한다. 볼록다각형이 격자점 위에 있으므로 픽의 정리를 이용하면 다각형 내부에 있는 점의 개수를 구할 수 있다. 여기서 볼록다각형의 내부에 있는 보호막의 개수만큼 빼면 답이 된다.
미사일의 수가 2개 이하인 경우는 볼록다각형이 만들어지지 않으므로 예외처리를 해줘야하는데, 다 짜고 이 예외처리 부분을 짜다가 대회가 끝났다. 딱 3분만 더 있었다면 맞을 수 있었는데 매우 아쉽다.