ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 20106: Cave
    코딩 2022. 2. 23. 20:40

    https://www.acmicpc.net/problem/20106

     

    20106번: Cave

    While lost on the long walk from the college to the UQ Centre, you have stumbled across the entrance to a secret cave system running deep under the university. The entrance is blocked by a security system consisting of N consecutive doors, each door behind

    www.acmicpc.net

    번역본은 https://oj.uz/problem/view/IOI13_cave를 참고하시면 됩니다.

     

    풀이

    시행이 최대 70,000번이며, $N$이 최대 5,000이기 때문에 $N\lg N$번의 tryCombination함수 호출로 문제를 해결해야 합니다. 즉, 하나의 스위치당 $\lg N$번의 시행으로 정답 위치와 연결된 문을 찾으면 됩니다.

     

    당연하게도 이분탐색으로 접근하면 됩니다. $ans[i]$를 스위치 $i$의 정답 위치, $match[i]$를 스위치 $i$에 연결된 문이라고 선언합니다. $0$번부터 $N-1$번까지의 문에 대해 순서대로 $match[i]$값이 그 문의 값이 되는 $i$를 이분탐색으로 찾아보도록 하겠습니다.

    현재 $i$번 문에 연결된 스위치를 찾는 상태라면, $0$부터 $i-1$번 문까지는 연결된 스위치와 그 스위치의 정답 위치를 알고 있을 것입니다. 그 $i$개의 스위치들을 모두 정답 위치로 고정해놓고, 나머지 스위치는 모두 상태 $0$으로 돌려놓고 tryCombination()함수를 호출하여 초기 $i$번 문의 상태를 저장합니다(함수의 리턴값이 $i$면 닫힌 상태, $i$가 아니면 열린 상태).

    $l$번부터 $r$번 사이에 저희가 찾는 스위치가 있다고 합니다(초기에는 $l=0,\ r=N-1$이 됩니다). $mid=(l+r)/2$라 하고, 스위치 $l$번부터 $mid$번까지를 앞서 고정한 스위치들을 빼고 모두 반전시킵니다. 그리고 tryCombination함수를 호출하여 문 $i$가 상태가 이전과 바뀌었는지 확인해봅니다. 만일 바뀌었다면, 문에 연결된 스위치는 반전시킨 구간인 $l$부터 $mid$ 중에 있는 것이고, 바뀌지 않았다면 $mid+1$부터 $r$ 중에 있는 것입니다. 이를 $\lg N$번 반복하여 문 $i$와 연결된 스위치를 찾을 수 있습니다.

    그 스위치의 정답 위치는 이분탐색 종료 직전에 확인한 문 $i$의 상태와 스위치의 상태로 구할 수 있습니다.

     

    코드

    더보기

     

    #include "cave.h"
    #include <bits/stdc++.h>
    using namespace std;
    int ans[5000], match[5000];
    void exploreCave(int n) {
        memset(match, -1, sizeof(match));
        for(int i=0; i<n; i++) {
            int s[5000]={0};
            for(int j=0; j<n; j++) if(match[j]!=-1) s[j]=ans[j];
            bool b=(tryCombination(s)==i);
            int l=0, r=n-1;
            while(l<r) {
                int mid=(l+r)/2;
                for(int j=l; j<=mid; j++) if(match[j]==-1) s[j]=!s[j];
                bool t=(tryCombination(s)==i);
                if(t==b) l=mid+1;
                else b=t, r=mid;
            }
            match[l]=i;
            ans[l]=s[l]^b;
        }
        answer(ans, match);
    }

     

    '코딩' 카테고리의 다른 글

    CodeTON Round 1 (Div. 1 + Div. 2)  (0) 2022.03.26
    백준 16238: 독수리  (0) 2022.03.09
    백준 20085: Detecting Molecules  (1) 2022.02.22
    백준 21761: 초직사각형  (3) 2022.01.28
    백준 1115: 순열  (0) 2022.01.13

    댓글

Designed by Tistory.