Movatterモバイル変換


[0]ホーム

URL:


Logo

IOI 2016 Aliens 풀이 (BOJ 20090)

안녕하세요. 이 글에서는 IOI 2016에 출제된Aliens 문제 풀이를 설명해보려고 합니다. 하나의 글 안에서 풀이 전체를 설명하는 것이 목표입니다.

풀이에 앞서 먼저 이 문제를 요약해보겠습니다. 왼쪽 그림과 같이 한 변의 길이가 m인 정사각형 격자가 주어지고, 그 안에 있는 n개의 점이 주어집니다. 정사각형으로 n개의 점을 모두 덮는 게 목표입니다. 이때, 정사각형은 가운데 그림에서 보는 것과 같이 왼쪽 위와 오른쪽 아래가 모두 대각선 위에 있어야 합니다. 정사각형은 서로 겹칠 수 있으며, 겹치는 영역은 한 번만 덮은 것으로 간주합니다. 같은 칸에 2개 이상의 점이 있다고 해도 한 번만 덮으면 충분합니다. 정사각형은 최대 k개만 사용할 수 있습니다. 우리는 덮은 칸의 개수를 최소화하고 그 개수를 출력해야 합니다.Aliens_SampleImage

풀이는 두 가지 부분으로 나눠서 설명하겠습니다.

  • 첫 번째 부분에서는 사용할 수 있는 정사각형의 개수 상한 k가 없을 때에 한해 문제를 해결합니다.
  • 두 번째 부분에서는 첫 번째 부분의 결과를 이용해 어떻게 k를 반영한 답을 구할 수 있는지 설명합니다.

1. 부분문제 1 풀이

1.1 좌표 전처리

  • 정사각형의 두 꼭짓점이 대각선 위에 있어야 하므로, 그 좌표를 각각 (a, a)와 (b, b)라고 합시다(a <= b). 그러면 이 정사각형은 두 좌표가 모두 a 이상 b 이하인 모든 점을 덮고, 그 이외의 점은 덮지 않습니다. 이를 앞으로 "정사각형 (a, a) - (b, b)"라고 쓰겠습니다.
  • 만약 좌표 (r, c)에 점이 있다면, 일반성을 잃지 않고 r <= c라고 가정할 수 있습니다. 왜냐면 (r, c)를 덮는 정사각형은 항상 (c, r)도 덮고, 반대로 (c, r)을 덮는 정사각형은 (r, c)도 덮으므로 이 가정이 문제의 답을 바꾸지 않기 때문입니다.
  • 정사각형 (a, a) - (b, b)가 점 (r, c)를 덮는다면, a <= r <= c <= b가 성립합니다. 따라서, 어떤 점 (r', c')이 존재하여 r <= r' <= c' <= c를 만족한다면, 점 (r, c)를 덮는 모든 정사각형이 (r', c')를 덮습니다. 따라서, (r', c')를 제거해도 문제의 답이 바뀌지 않습니다.
  • 이상의 논의로부터, 주어진 점을 답을 바꾸지 않으면서 전처리하고 정렬하여 r과 c가 모두 증가(strictly increasing)하도록 할 수 있음을 알 수 있습니다. 이를 순서대로 (r_1, c_1), ..., (r_n, c_n)이라고 하겠습니다. (단, 여기서 n은 전처리 이후의 점의 개수를 의미하며, 입력으로 주어진 n과 다를 수 있습니다.)

1.2 DP Formulation

  • 만약 어떤 i < j < k에 대해 정사각형 (a, a) - (b, b)가 (r_i, c_i)와 (r_k, c_k)를 모두 커버한다면, a <= r_i <= r_j <= r_k <= b 및 a <= c_i <= c_j <= c_k <= b로부터 해당 정사각형이 (r_j, c_j)도 커버합니다. 따라서 각 정사각형이 n개의 점을 커버하는 형태는 "i부터 j까지"의 연속된 구간을 커버하는 형태임을 알 수 있습니다.
  • 각 정사각형의 커버리지는 서로 겹치지 않는 경우만 고려해도 충분함을 보일 수 있습니다.
  • 이는 DP 상태정의를 어떻게 할지에 대한 힌트가 됩니다. "점 i"는 "점 (r_i, c_i)"를 의미한다고 할 때, "DP[i, j] = (가장 마지막 정사각형이 점 i부터 점 j까지를 커버할 때, 점 1부터 점 j까지 커버하는 최소 비용"이라고 정의할 수 있습니다.

점화식은 어떻게 될까요? 구간 [i, j]를 커버했으면, 직전의 커버리지는 어떤 k에 대해 [k, i-1]을 커버했을 것입니다. 따라서, 각 k에 대해 DP[k, i-1] + (점 i부터 점 j까지 커버하는 비용)의 최솟값을 구하면 될 것입니다. 이때, 두 가지 경우를 고려해야 합니다.

  • $r_i \le c_{i-1}$인 경우: 새로 추가하는 정사각형의 일부분은 직전 정사각형에 의해 이미 커버되어 있습니다. 이 부분을 빼야 새로 추가되는 비용을 정확히 계산할 수 있습니다.
  • $r_i > c_{i-1}$인 경우: 새로 추가하는 정사각형은 기존에 커버된 영역과 겹치지 않습니다. 따라서 특별히 빼야 하는 비용이 없습니다.

이로부터 O(n^3)의 DP가 유도됩니다.

1.3 DP Optimization

  • 상태정의를 잘 관찰하면, DP[i, j]에서 i가 중요하지 않다는 것을 알 수 있습니다. 따라서 j만 남겨 DP[j]를 고려해도 충분합니다. 이로부터 O(n^2)의 DP가 유도됩니다.
  • DP식을 세우면 Convex Hull Trick이 적용되는 형태라는 것을 알 수 있습니다. 구현에 따라 O(n) 또는 O(n lg n)으로 최적화가 가능합니다.

1.4 Notes

  • 정사각형 개수에 따라 p의 패널티를 주도록 변경할 수 있습니다. 즉, 정사각형 x개를 사용한다면 (해당 솔루션의 최소비용) + x * p를 최소화하도록 계산을 할 수 있다는 의미입니다. 이때, DP 식과 CHT 최적화는 동일하게 유지할 수 있습니다.
  • 또한, 해당 최소 비용을 갖는 솔루션이 몇 개의 정사각형을 사용했는지 추적할 수 있습니다(argmin).

이 두 가지 사실은 다음 절에서 중요하게 사용됩니다.

2. 전체 문제 풀이

이제부터 Aliens trick이라고 불리는 부분입니다. 지금까지 우리는 k를 고려하지 않고 문제를 해결하였습니다. k를 고려하기 위해서는 어떻게 해야 할까요?

  • C[i] = (정확히 i개의 정사각형을 사용할 때의 최소 비용)이라고 정의합시다. C[i]는 i에 대해 단조감소합니다. 그러나 단조감소 자체가 중요한 것은 아닙니다.
  • 우리는 C[i-1] + C[i+1] >= 2C[i]라는 것을 증명할 수 있습니다. 즉, C[i]는 i에 대해 아래로 볼록합니다.

이것을 일단 받아들인다면, 매개변수 탐색을 이용하여 문제를 해결할 수 있습니다.

  • Case 1: 만약 전역 최솟값이 1 <= i <= k인 어떤 i에서 발생한다면, 그냥 k를 무시하고 전체 문제를 풀면 됩니다.
  • Case 2: 만약 전역 최솟값이 i > k인 어떤 i에서만 발생한다면, 구하는 답은 C[1..k] 중 최솟값이 됩니다. 그런데 볼록성에 의해 이는 C[k]와 같습니다.

갑자기 전역 최솟값이 발생하는 위치를 찾는 문제가 중요해졌습니다. 이는 우리가 각 i에 대해 C[i]를 모두 알고 있다면 아주 쉬운 문제입니다. 그렇지만 현재 상황이 그렇지 않으니 대안을 찾아봐야 합니다. 한 가지 방법은 접선을 사용하는 것입니다. 상황을 단순화하기 위해 먼저 인접한 두 값의 차이 C[i] - C[i-1]이 증가(strictly increasing)하는 경우를 생각해봅시다. 이 경우 기울기에 대한 매개변수 탐색을 할 수 있습니다. 만약 기울기 p인 접선이 C[i]와 접하는 위치가 j라면, 이 j는 패널티 -p를 주고 1.4절의 내용에 따라 문제를 풀어서 나온 argmin과 같습니다. 따라서, 이 argmin j가 j <= k를 만족하도록 하는 p 중 최댓값을 구하고 이를 p_max라고 합시다.

  • 만약 p_max > 0이라면, C[i]는 i=k에서 증가하고 있습니다. 이는 대략 Case 1에 해당합니다.
  • 만약 p_max < 0이라면, C[i]는 i=k에서 감소하고 있습니다. 이는 대략 Case 2에 해당합니다.

그러나 "strictly" increasing이 보장되지 않고 "monotonically" increasing할 수도 있는 경우에는 문제가 생깁니다.다음과 같은 입력을 생각해봅시다.

4 100 30 01 14 45 5

이 경우 C[1] = 36, C[2] = 8, C[3] = 6, C[4] = 4입니다. k=3이므로 구하는 답은 C[3]=6입니다. p_max = -2입니다. 그런데 패널티 -p_max를 주고 구한 결과에서 argmin은 2, 3, 4 중 어느 것이든 될 수 있습니다. 따라서 문제가 발생할 수 있습니다.

이를 해결하기 위해서 기울기를 정수가 아니라 (정수 + 0.5) 형태로 두고 이분탐색을 하는 트릭을 사용할 수 있습니다. 이렇게 정의하면 패널티 -p_max를 주고 구한 결과에서 argmin은 반드시 유일하게 결정되며, argmin <= k가 보장됩니다. 또한, p_max는 절대로 0이 되지 않아 생각하기에 편리합니다.

  • 만약 p_max > 0이라면, argmin에 관계없이 C[i]는 i=k에서 증가하고 있습니다. 이는 Case 1에 해당합니다.
  • 만약 p_max < 0이고 argmin < k라면, 그래프는 i=argmin에서 꺾이고 i=k까지 직선의 형태를 유지합니다. 이는 Case 2에 해당합니다.
  • 만약 p_max < 0이고 argmin = k라면, 그래프는 i=k에서 꺾입니다. 이는 Case 2에 해당합니다.

위에서 예시로 든 입력에서는 p_max = -5/2이고 argmin = 2입니다. 따라서 Case 2에 해당합니다.

마지막 단계를 정리하고 이 절을 맺겠습니다.

  • Case 1의 경우 패널티 없이 구하면 충분하다고 위에서 설명했습니다.
  • Case 2의 경우 주의가 필요합니다. 매개변수 탐색의 성질에 따르면 i=argmin에서 i=k까지(또는 그보다 더 나갈 수도 있음)의 구간은 기울기 p_max + 1/2를 갖고 있습니다. 따라서 패널티 -p_max - 1/2를 주고 문제를 풀면 해당 구간에서의 답을 구할 수 있습니다. 단, 이때 구한 답의 argmin은 우리가 원하는 값이 아닐 수 있으므로, 이것 대신 k라고 생각하고 답을 구해야 합니다.

3. C[i]의 볼록성 증명

이 부분은 매우 기술적(technical)입니다. C[i-1]와 C[i+1]의 최소 비용 솔루션 중 하나를 각각 A, B라고 합시다. 구간 분절점 중 서로 중복되지 않는 것을 모아 각각 P(A), P(B)라고 합시다. 그러면 P(B)는 P(A)보다 정확히 두 개의 분절점을 더 갖고 있습니다. 순서대로 볼 때 P(B)에 연속되는 3개의 분절점이 있다면, 그 중 가운데 분절점을 P(A)로 올려보내면 총합을 증가시키지 않으면서 정사각형을 정확히 i개 사용하는 두 개의 솔루션을 만들 수 있습니다. 만약 그렇지 않다면, |P(B)| = |P(A)| + 2로부터 P(B)에는 연속되는 2개의 분절점이 반드시 존재해야 합니다. 만약 P(A)에 있는 분절점을 a, P(B)에 있는 분절점을 b라고 한다면, abba (만약 시작이나 끝에 존재하는 경우 abb나 bba일 수 있지만, 논리는 동일하게 성립함)가 존재합니다. 이때 abba를 ab와 ba로 분절하고 교차(crossover)시키면 총합은 증가하지 않습니다. 이때, P(B)의 누적 알짜 개수 우위는 0에서 시작하여 2로 끝나야 하는데, bbb의 존재 불가성으로 인해 한 번에 최대로 증가시킬 수 있는 알짜 개수는 1이므로, 어떤 bba가 존재하여 알짜 개수가 0에서 1로 되는 순간이 있어야 합니다. bbba는 불가능하므로 이는 abba였어야 하고, 결과적으로 이 abba의 가운데를 분할하고 교차시키면 총합을 증가시키지 않으면서 정사각형을 정확히 i개 사용하는 두 개의 솔루션을 만들 수 있습니다. 이렇게 구한 두 솔루션의 값을 x, y라고 하면, C[i-1] + C[i+1] >= x + y >= 2C[i]가 성립하여 결론이 증명됩니다.

긴 글 읽어주셔서 감사합니다.


댓글 (2개)댓글 쓰기


hitters1년 전

좋은 글 감사합니다!!ㅓ^ㅇ^ㅏ


readiz1년 전

잘 읽었습니다. 감사합니다.

검색

목록보기

최신 글

Python3 vs Pypy3

빅-O, 빅-Ω, 빅-Ө는 최악, 최선, 평균을 의미하지 않습니다.

solved.ac 조건 숨겨진 배경 힌트 드림📢

31442번 좋은 수열 문제의 오토마타 기반 풀이

제3회 초콜릿컵/Arena #23 문제 오류에 대한 사과문 및 출제 검수 과정 복기

solved.ac Grand Arena Party 후기

IOI 2016 Aliens 풀이 (BOJ 20090)

[C++] tie 와 sync_with_stdio

Zeta, Mobius Transform to AND, OR, GCD Convolution

월간 향유회 2023. 5. 풀이

출처

대학교 대회

  • 사업자 등록 번호: 541-88-00682
  • 대표자명: 최백준
  • 주소: 서울시 서초구 서초대로74길 29 서초파라곤 412호
  • 전화번호: 02-521-0487 (이메일로 연락 주세요)
  • 이메일:contacts@startlink.io
  • 통신판매신고번호: 제 2017-서울서초-2193 호


[8]ページ先頭

©2009-2025 Movatter.jp