Kickstart

Google Kickstart 2019 Round D – ‘X or What’ 풀이 (코드포함)

이 포스팅에서는 Google Kickstart 2019 Round D ‘X or What’의 풀이와 코드를 제공합니다.
본 풀이는 공식적인 풀이와 완벽히 일치하지 않을 수 있으며, 온라인 Submission을 통과하였습니다.
공식 풀이 및 자세한 사항은 공식 페이지를 참조하시기 바랍니다.


Prob A ‘X or What’

문제 정보

문제 링크 : https://codingcompetitions.withgoogle.com/kickstart/round/0000000000051061/0000000000161426
카테고리 : Bit manipulation, Heap
난이도 : 중간

문제 설명

테스트 케이스의 수 T가 주어진다.
그 다음 줄에는 배열의 길이 N과 쿼리의 수 Q가 주어진다.
그 다음 줄에는 배열의 원소인 정수 A_0, A_1, … , A_N-1이 입력된다.
그 다음 Q개의 줄에는 배열 인덱스와 새로운 값을 가리키는 P_i, V_i가 입력된다.
이 쿼리의 연산은 A[P_i]의 값을 V_i로 바꾸는 연산이다.
각 쿼리를 수행한 후, 배열 A의 SubArray 중 모든 원소를 Xor해서 2진수로 표현할 때 1이 짝수 개인 SubArray 중 가장 긴 것의 길이를 출력하여라.

예를 들어, 원래 배열이 3 3 3 3 3 3 3 3 3 3 이라고 하자.
여기서 쿼리 1 4 를 수행하면 3 4 3 3 3 3 3 3 3 3 의 배열을 얻는다.
여기서 가능한 가장 긴 SubArray는 인덱스 (2, 9)의 구간인 3 3 3 3 3 3 3 3 이다.
따라서 길이 8이 출력된다.
여기서 쿼리 2 4를 수행하면 3 4 4 3 3 3 3 3 3 3 을 얻는다.
여기서 가장 가능한 긴 SubArray는 인덱스 (0, 9)의 구간인 3 4 4 3 3 3 3 3 3 3 이다.
따라서 길이 10을 출력한다.

문제 풀이

2진수로 표현했을 때, 비트 수가 홀수 인 것을 odd, 짝수인 것을 even이라고 하자.
문제 해결의 핵심 아이디어는 odd와 odd를 xor하면 even이 된다는 점이다.
예를 들어 7(111)과 4(100)를 xor하면 3(11)이 된다. 증명은 간단하다.
두 수가 공유하는 1의 비트는 xor로 사라진다. 서로 공유하지 않는 1의 비트는 xor 결과에서 별개로 존재하므로 그 수를 각각 더해야한다.
공유하는 1의 비트가 짝수라면 서로 공유하지 않는 1의 비트는 각각 홀수개라 더하면 짝수가된다.
공유하는 1의 비트가 홀수개라도 남은 비트가 각각 짝수이므로 역시 더하면 짝수가된다.

즉, 결론은 다음과 같다.
쿼리를 수행한 이후에 배열의 odd가 짝수개 있으면 배열의 길이 자체가 답이된다.
만약 odd가 홀수 개 있다면, 배열의 가장 왼쪽이나 오른쪽의 원소까지를 제외한 나머지 길이 중 큰 것이 답이된다.

코드
import Queue

def countBit(N):
    ret = 0
    while N > 0:
        ret += (N % 2)
        N //= 2
    return ret % 2

def findMaxLength(Min_Q, Max_Q, Nums, N):
    left, right = None, None
    while not Min_Q.empty():
        idx, val = Min_Q.get()
        if Nums[idx] == val:
            left = [idx, val]
            Min_Q.put([idx, val])
            break
    
    while not Max_Q.empty():
        idx, val = Max_Q.get()
        if Nums[-idx] == val:
            right = [-idx, val]
            Max_Q.put([idx, val])
            break
    
    if N - left[0] - 1 > right[0]:
        return N - left[0] - 1
    else:
        return right[0]
        
        
T = int(input())
for case in range(1, T + 1):
    # Get Input
    N, Q = [int(x) for x in raw_input().split(' ')]
    Nums = [int(x) for x in raw_input().split(' ')]
    
    # Init Priority Queue
    Min_Q = Queue.PriorityQueue()
    Max_Q = Queue.PriorityQueue()
    oddCnt = 0
    
    # Calc initial state of array
    for i in range(N):
        if countBit(Nums[i]) == 1:
            oddCnt += 1
            Min_Q.put([i, Nums[i]])
            Max_Q.put([-i, Nums[i]])

    result = []
    # For each query, handle element according oddness of bits.
    for i in range(Q):
        idx, newVal = [int(x) for x in raw_input().split(' ')]
        if countBit(newVal) == 1:
            Min_Q.put([idx, newVal])
            Max_Q.put([-idx, newVal])
            if countBit(Nums[idx]) == 0:
                oddCnt += 1
        elif countBit(newVal) == 0:
            if countBit(Nums[idx]) == 1:
                oddCnt -= 1
        Nums[idx] = newVal
        
        # If number of oddbits is odd, calc max length.
        if oddCnt % 2 == 0:
            result.append(str(N))
        else:
            result.append(str(findMaxLength(Min_Q, Max_Q, Nums, N)))
    
    print "Case #" + str(case) + ": " + " ".join(result)

Competition Kickstart ‘X or What’

admin

Recent Posts

2024년 11월 17일 일요일 – 서울 생활 129주차

괌여행 아내와 함께 괌으로 여행을 갔다. 출산 이후로 둘만 가는 첫 여행이다. 하와이가 일본인들이 많이…

3일 ago

2024년 11월 3일 일요일 – 서울 생활 127주차

반복적인 일상 매일 아침 일어나 회사에 출근하고, 저녁을 먹고 돌아오는 일상의 반복이다. 주말은 가족을 보러…

3주 ago

2024년 10월 6일 일요일 – 서울 생활 123주차

Planning A well-structured plan has the following characteristics:   First, the ultimate vision you aim to…

2개월 ago

2024년 9월 29일 일요일 – 서울 생활 122주차

English The most common problem for English learners like myself is that we often use…

2개월 ago

2024년 9월 22일 일요일 – 서울 생활 121주차

추석 추석을 맞아 친가 외가 처가 어르신들을 모두 뵙고 돌아왔다. 아이가 태어난지는 좀 됐지만 한국에서…

2개월 ago

2024년 9월 8일 일요일 – 서울 생활 119주차

주말 이번주는 아내가 올라와서 주말을 함께 보냈다. 둘만 밥도 먹고 뮤지컬도 보고, 모임도 나가고 집에서…

2개월 ago

This website uses cookies.