문제 분류 수업 진도 대회 채점현황 순위 질문게시판
게임
스도쿠 타이핑 리듬 타자게임 타이핑 테트리스 타이핑 인베이더 타이핑 지뢰찾기 8192 공룡게임 타이핑 플래피버드 랭킹
로그인
← 수업 목록
▶ 슬라이드 시작

Ch 11. 수학 (Mathematics)

수업 목표

본 수업은 알고리즘 해결과 암호학의 기반이 되는 정수론, 조합론, 선형대수학의 핵심 원리를 이해하고, 파이썬을 이용한 고속 모듈러 산술과 게임 이론 알고리즘을 설계할 수 있는 능력을 기르는 것을 목표로 합니다. - 분할 정복을 활용한 빠른 거듭제곱과 페르마의 소정리를 결합하여 지수가 극도로 큰 모듈러 거듭제곱을 최적화합니다. - 모듈러 역원을 $O(N)$에 전처리하여 여러 개의 이항 계수($\binom{n}{r}$) 쿼리를 $O(1)$에 즉시 해결하는 조합 기법을 습득합니다. - 피보나치 등 선형 점화식의 관계를 행렬식으로 변환하고 행렬 거듭제곱을 이용해 $O(\log N)$ 시간에 연산하는 기법을 구현합니다. - 스프라그-그룬디 정리(Sprague-Grundy Theorem)와 XOR 합(Nim-sum)의 수학적 대칭성을 규명하고 님 게임의 승패 판정에 적용합니다.

학습 동기부여

컴퓨터 알고리즘 설계와 보안 암호학(예: RSA 비대칭키 암호화)에서 수학적 원리의 적용은 병목을 해결하는 결정적 무기입니다. 예를 들어 10의 18승 단계의 피보나치 수를 일반 DP로 연산하면 인류의 일생을 다 바쳐도 끝나지 않지만, 행렬 거듭제곱 최적화를 적용하면 단 0.001초 만에 연산이 완료됩니다. 또한 포함배제, 조합론의 팩토리얼 역원 계산은 대규모 경우의 수를 다루는 핵심 도구입니다. 본 수업에서 다루는 모듈러 대수와 수학적 모델들은 계산의 한계를 뛰어넘어 초고속 고성능 시스템을 구축할 수 있게 돕습니다.

도입 스토리

두 사람이 돌 무더기들 앞에 앉아 번갈아 돌을 가져가는 고대의 보드 게임이 있습니다. 마지막 돌을 가져가는 자가 이기는 이 단순한 놀이는 얼핏 보면 상대방의 심리를 꿰뚫고 직관에 의존해야 이길 수 있을 것처럼 보입니다. 그러나 사실 모든 돌 무더기의 개수를 이진수로 변환하고 비트별로 더한 값(XOR 합)을 계산해 보면, 이 게임의 승패 결과는 게임을 시작하기도 전에 선공과 후공 중 누구에게 필승 경로가 있는지 수학적으로 완벽히 정해져 있습니다. 이처럼 복잡해 보이는 세계의 흐름을 단 몇 개의 비트 연산으로 규명해 내는 모듈러 대수와 조합 게임 이론의 강력함을 본 수업에서 파헤쳐 봅니다.

1. 수론 - 빠른 거듭제곱과 페르마의 소정리

분할 정복 기반의 거듭제곱은 $O(\log N)$에 $a^b \pmod m$을 구합니다. 소수 $p$에 대해 $a^{p-1} \equiv 1 \pmod p$가 성립한다는 페르마의 소정리를 이용하면 지수 부분이 또 다른 거듭제곱 형태인 $b^c$로 주어질 때 지수 자체에 모듈러 $p-1$을 법으로 먼저 적용함으로써 연산의 범위를 획기적으로 낮출 수 있습니다.
# 8057번: 빠른 거듭제곱 II — 지수에 p-1 모듈러를 적용한 고속 연산
import sys
input = sys.stdin.readline

def power(base, exp, mod):
    res = 1
    base %= mod
    while exp > 0:
        if exp % 2 == 1:
            res = (res * base) % mod
        base = (base * base) % mod
        exp //= 2
    return res

n = int(input())
p = 1000000007
for _ in range(n):
    a, b, c = map(int, input().split())
    # 페르마 소정리에 의해 지수부 b^c에 p-1 모듈러를 먼저 적용
    exp = power(b, c, p - 1)
    print(power(a, exp, p))

2. 조합론 - 이항 계수와 역원 전처리

조합의 수 $\binom{n}{r} = \frac{n!}{r!(n-r)!} \pmod p$를 여러 쿼리에 대해 빠르게 해결하려면 팩토리얼 수열과 그 역원을 미리 계산해야 합니다. 페르마 소정리에 의해 $x^{-1} \equiv x^{p-2} \pmod p$임을 사용하여 최대 크기 $N$의 역원 inv_fact[N]을 먼저 구한 뒤, 역순으로 inv_fact[i] = inv_fact[i+1] * (i+1) % p 공식을 적용하면 단 $O(N)$ 시간 안에 1부터 $N$까지의 모든 팩토리얼 역원을 구해두고 각 조합 질의를 $O(1)$에 해결할 수 있습니다.
# 8058번: 이항 계수 쿼리 — O(N) 전처리 후 O(1) 조합 합산
import sys
input = sys.stdin.readline

p = 1000000007
MAX = 1000000

# 팩토리얼 배열 전처리
fact = [1] * (MAX + 1)
for i in range(2, MAX + 1):
    fact[i] = (fact[i - 1] * i) % p

# 페르마 소정리 역원 전처리
def power(base, exp):
    res = 1
    base %= p
    while exp > 0:
        if exp % 2 == 1:
            res = (res * base) % p
        base = (base * base) % p
        exp //= 2
    return res

inv_fact = [1] * (MAX + 1)
inv_fact[MAX] = power(fact[MAX], p - 2)
# 역순 전파를 통해 O(N)에 전체 역원 테이블 구축
for i in range(MAX - 1, -1, -1):
    inv_fact[i] = (inv_fact[i + 1] * (i + 1)) % p

n = int(input())
for _ in range(n):
    a, b = map(int, input().split())
    if b < 0 or b > a:
        print(0)
    else:
        ans = (fact[a] * inv_fact[b]) % p
        ans = (ans * inv_fact[a - b]) % p
        print(ans)

3. 행렬 거듭제곱과 피보나치 점화식

점화식 $F_n = F_{n-1} + F_{n-2}$의 항 전이를 선형대수의 행렬 곱셈 관계로 식을 정립하면 다음과 같이 변환할 수 있습니다: $\begin{pmatrix} F_{n+1} \\ F_n \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix} \begin{pmatrix} F_n \\ F_{n-1} \end{pmatrix} \implies \begin{pmatrix} F_{n+1} \\ F_n \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}^n \begin{pmatrix} F_1 \\ F_0 \end{pmatrix}$ 따라서 $2 \times 2$ 기본 행렬을 분할 정복 거듭제곱 기법으로 빠르게 제곱하여 $O(\log N)$에 극도로 큰 인덱스의 피보나치 수를 오차 없이 모듈러 산술로 계산할 수 있습니다.
# 8059번: 피보나치 수열 — O(log N) 행렬 거듭제곱 최적화
import sys
input = sys.stdin.readline

def multiply(A, B, mod):
    C = [[0, 0], [0, 0]]
    for i in range(2):
        for j in range(2):
            s = 0
            for k in range(2):
                s = (s + A[i][k] * B[k][j]) % mod
            C[i][j] = s
    return C

def power_matrix(A, n, mod):
    res = [[1, 0], [0, 1]]
    base = A
    while n > 0:
        if n % 2 == 1:
            res = multiply(res, base, mod)
        base = multiply(base, base, mod)
        n //= 2
    return res

n = int(input())
if n == 0:
    print(0)
else:
    p = 1000000007
    T = [[1, 1], [1, 0]]
    # T^(n-1) 행렬의 [0][0] 번째 원소가 F_n에 대응됨
    res = power_matrix(T, n - 1, p)
    print(res[0][0])

4. 게임 이론 - 님 게임 (Nim Game)

님 게임은 각 플레이어가 번갈아가며 한 더미에서 돌을 임의로 제거하고 마지막 돌을 제거하는 사람이 승리하는 공평 게임(Impartial Game)입니다. - **스프라그-그룬디 정리**: 모든 더미의 돌 개수의 XOR 비트합 $S = x_1 \oplus x_2 \oplus \dots \oplus x_n$ (Nim-sum)을 구합니다. - $S \neq 0$인 경우 선공의 필승 상태(Winning State)입니다. 선공은 적절히 돌을 제거하여 XOR 합을 항상 $0$으로 만들어 후공을 패배 상태로 밀어 넣을 수 있습니다. - $S = 0$인 경우 후공의 필승 상태(Losing State)입니다. 선공이 어떤 돌을 가져가도 다음 상태의 XOR 합은 무조건 0이 아닌 값이 되므로 후공이 이를 다시 0으로 통제할 수 있습니다.
# 8060번: 님 게임 — XOR 비트 연산으로 O(N) 판정
import sys
input = sys.stdin.readline

t = int(input())
for _ in range(t):
    n = int(input())
    x = list(map(int, input().split()))
    
    xor_sum = 0
    for num in x:
        xor_sum ^= num
        
    if xor_sum != 0:
        print("first")
    else:
        print("second")

자주 하는 실수 & 오류 예방

- 지수 모듈러의 오용: $a^{b^c} \pmod p$를 풀 때 지수 $b^c$에 동일한 모듈러 $p$를 적용하면 오답이 됩니다. 지수부에는 오일러의 정리 및 페르마의 소정리에 따라 반드시 $p-1$ (즉, $10^9+6$)을 모듈러로 적용하여 계산하십시오. - 음수 뺄셈 후 모듈러 보정: 모듈러 곱셈 역원을 이용하여 나눗셈 구간의 뺄셈 조합을 진행할 때, 뺄셈 연산 결과가 음수가 되는 것을 대비해 (A - B + p) % p 형태로 보정값을 취해야 파이썬 및 기타 언어에서 음수 모듈러에 의한 불규칙 에러를 원천 차단할 수 있습니다. - 피보나치 행렬 연산 $N=0$ 예외: $N=0$ 일 때 행렬 승수 연산 진입 시 $n-1 = -1$이 되어 루프 무한 루프나 인덱스 침범이 나지 않도록 함수의 초입부에 예외 필터링 조건을 두어야 합니다.

핵심 정리

알고리즘 및 정리 시간 복잡도 공간 복잡도 법(Modulo) 기준 주요 적용 주제
페르마 소정리 지수 감축 $O(\log c + \log \text{exp})$ $O(1)$ 지수는 $p-1$, 밑은 $p$ 적용 다중 거듭제곱 탑 형태의 빠른 모듈러 연산
선형 팩토리얼 역원 전처리 $O(MAX)$ 전처리, 쿼리 $O(1)$ $O(MAX)$ 소수 $p$ 이항 계수 및 조합 경우의 수 쿼리 다량 처리
행렬 거듭제곱 (Matrix Exp) $O(\log N)$ (상수 크기 행렬) $O(1)$ 소수 $p$ 인덱스가 $10^{18}$에 달하는 점화식 수열 계산
그룬디 Nim-sum 판정 $O(N)$ (단일 스캔) $O(1)$ 비트 XOR 연산 공평 조합 게임의 필승 전략 선/후공 판정

실습 문제

문제 번호 문제 제목 출처 난이도 핵심 알고리즘
8057 빠른 거듭제곱 II CSES 쉬움 페르마의 소정리 & 거듭제곱
8058 이항 계수 쿼리 CSES 보통 팩토리얼 역원 전처리 & 조합론
8059 피보나치 수열 CSES 보통 행렬 거듭제곱 & 분할 정복
8060 님 게임 CSES 보통 게임 이론 & 그룬디 XOR 합
NOTICE  —  BFStudy OJ 정보샘
애들아, 문제 많이 풀고 게임 잠깐 하는거지?
— 정보샘