목차

소수 징글벨

ps
링크acmicpc.net/…
출처BOJ
문제 번호23633
문제명소수 징글벨
레벨골드 3
분류

게임 이론

시간복잡도O(nloglogn + T*n)
인풋사이즈T<=10, n<=2000
사용한 언어Python 3.11
제출기록33376KB / 48ms
최고기록48ms
해결날짜2023/07/04

풀이

코드

코드 1 - O(n^2) dp

"""Solution code for "BOJ 23633. 소수 징글벨".

- Problem link: https://www.acmicpc.net/problem/23633
- Solution link: http://www.teferi.net/ps/problems/boj/23633

Tags: [game theory]
"""

from teflib import numtheory


def main():
    T = int(input())
    A_and_B = [[int(x) for x in input().split()] for _ in range(T)]

    max_b = max(b for _, b in A_and_B)
    primes = set(numtheory.prime_list(max_b))

    for a, b in A_and_B:
        max_score = [None] * (b + 1)
        max_score[b] = 0
        remaining_score = 1 if b in primes else 0
        for i in reversed(range(b)):
            if i in primes:
                remaining_score += 1
            max_score[i] = remaining_score - min(
                max_score[j] for j in range(i + 1, min(i + a, b) + 1)
            )

        first_score = max_score[0]
        second_score = remaining_score - first_score
        if first_score > second_score:
            print('kuro')
        elif first_score < second_score:
            print('siro')
        else:
            print('draw')


if __name__ == '__main__':
    main()

코드 2 - O(n) greedy

"""Solution code for "BOJ 23633. 소수 징글벨".

- Problem link: https://www.acmicpc.net/problem/23633
- Solution link: http://www.teferi.net/ps/problems/boj/23633

Tags: [game theory]
"""

from teflib import numtheory

FIRST = 0
SECOND = 1


def main():
    T = int(input())
    A_and_B = [[int(x) for x in input().split()] for _ in range(T)]

    max_b = max(b for _, b in A_and_B)
    primes = set(numtheory.prime_list(max_b))

    last_prime = [0] * (max_b + 1)
    prime_count = [0] * (max_b + 1)
    lp, count = -1, 0
    for i in range(max_b + 1):
        if i in primes:
            lp = last_prime[i] = i
            count = prime_count[i] = count + 1
        else:
            last_prime[i], prime_count[i] = lp, count

    for a, b in A_and_B:
        pos = 0
        score = [0, 0]
        turn = FIRST
        while pos < b:
            lp = last_prime[min(pos + a, b)]
            if lp <= pos:
                pos += 1
            else:
                score[turn] += prime_count[lp] - prime_count[pos]
                pos = lp
            turn = 1 - turn

        if score[FIRST] > score[SECOND]:
            print('kuro')
        elif score[FIRST] < score[SECOND]:
            print('siro')
        else:
            print('draw')


if __name__ == '__main__':
    main()