본문 바로가기
PS/백준

[백준/BOJ] 27172번 - 수 나누기 게임 (Python)

by 행복한라이언 2023. 10. 17.
728x90
반응형

· 문제링크

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

 

27172번: 수 나누기 게임

《보드게임컵》을 준비하다 지친 은하는 보드게임컵 참가자들을 경기장에 몰아넣고 결투를 시키는 게임 《수 나누기 게임》을 만들었습니다. 《수 나누기 게임》의 규칙은 다음과 같습니다.

www.acmicpc.net

· 핵심 : 약수 + 시간복잡도 

문제 요약 : 내가 다른 수를 나눠서 나머지가 0이면 +1 득점, 나뉘어진 수를 가진 상대방은 -1 감점

1. 시간복잡도 계산

→ 바로 떠오르는 풀이는 이중 for문 써서 전부 확인하는 방법 

→ N = 100,000이므로 이중for문 사용하면 반드시 시간초과 발생 

2. 약수 구하기 

→ 제곱근까지만 확인하기 : 시간복잡도 O(N^(1/2))

3. +1 과 -1 의 의미 생각하기

+1 의 의미: 약수로 나를 가지고 있다! 각 숫자가 갖는 약수에서 내가 몇 번 등장했는지 체크하기

    Ex) 3 4 12 15 16 이 입력으로 들어올 때,약수에 3번이 총 몇 번 등장해? 12와 15에서 2번 등장! 따라서 3은 +1 * 2 획득 

→ -1의 의미: 특정 값의 약수인 내가 「입력으로 들어온 숫자들」 에 존재하면 어떻게 될까? 내가 나뉘어지므로 -1 감점 당한다.

    Ex) 3 4 12 15 16 이 입력으로 들어올 때, 12의 약수를 생각해보자. 1 2 3 4 6으로 그런데 약수 중 3과 4는 입력으로 들어온 숫자에 존재함. 그렇다는건 내가 3과 4로 나뉘어져서 -1 * 2 해서 2점을 감점 당하는 상황이라고 생각할 수 있음.


· 코드(Python)

# https://www.acmicpc.net/problem/27172
# 시간복잡도 : 이중포문 - 100 000 * 100 000 = 10^10 > 시간초과
# 내가 얻은 카드 숫자의 약수가 다른 사람에게 있는지 없는지 판단하는게 포인트!
from collections import Counter

def get_divisors(num):
    divisors = set()
    sqrt_num = int(num ** 0.5) + 1
    for i in range(1, sqrt_num):
        if num % i == 0:
            divisors.add(i)
            if i != 1 and i != num // i:
                divisors.add(num // i)
    return divisors

n = int(input())
nums = list(map(int, input().split()))

dic = {}
for num in nums:
    dic[num] = get_divisors(num)
    
scores = [0] * n

divisor_counter = Counter()
for key, value in dic.items():
    for div in value:
        if div in dic:
            divisor_counter[div] += 1
            divisor_counter[key] -= 1

for idx, num in enumerate(nums):
    scores[idx] = divisor_counter[num]

print(*scores)

 

728x90
반응형