BOJ 3955 캔디 분배
BOJ 3955 캔디 분배
문제
캔디 분배 https://www.acmicpc.net/problem/3955
각 봉지에 $K$개의 사탕이 들어있을 때, $y$봉지를 사서 $X$명에게 $x$개씩 나누어주고 1개가 남도록 하는 최소의 양의 정수 $y$를 구하는 문제. (단, $y \le 10^9$이며 $x > 0, y > 0$)
복잡도 분석
- time complexity : $O(\log(\min(K, C)))$ - 확장 유클리드 호제법의 시간 복잡도를 따르며, 최대 100개의 테스트 케이스를 제한 시간(1초) 내에 매우 여유롭게 통과함.
- space complexity : $O(\log(\min(K, C)))$ - 재귀 호출에 의한 Call Stack 메모리만 사용하며, 추가적인 자료구조 불필요.
접근법
- $C \cdot y - K \cdot x = 1$ 형태의 베주 항등식(Bézout’s Identity)으로 문제를 재구성.
- 확장 유클리드 알고리즘(Extended Euclidean Algorithm)을 사용하여 특수해와 $\gcd(K, C)$를 도출.
- $\gcd \neq 1$인 경우 해가 존재하지 않으므로 예외 처리.
- $y$를 양수로 보정하기 위해 $y = (y \pmod K + K) \pmod K$ 적용.
- “친구들에게 사탕을 나누어 준다($x > 0$)”는 물리적 제약 조건을 만족하기 위해 $C \cdot y \le 1$인 경우 $y$에 $K$를 가산.
- 최종 $y$가 상한선($10^9$)을 초과하는지 검증.
풀이
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import sys
input = sys.stdin.read
inp = input().replace('\x1a', '').splitlines()
def egcd(a,b):
if b==0:
return (a,1,0)
g,x1,y1= egcd(b,a % b)
x = y1
y = x1 - (a//b) * y1
return (g,x,y)
def solv(k,c):
# c*y = k*x + 1
# c*y - k*x = 1
# (-k) * x + c * y = 1
g,x,y = egcd(k,c)
y = (y%k + k) %k
# c*y가 1 이하라면 x가 0이하가 되어버린다.. 1 1 때문에 while
while c*y <= 1:
y+=k
if g != 1 or (y>1e9):
print("IMPOSSIBLE")
return
print(y)
for i,x in enumerate(inp):
if i>0:
a,b = map(int, x.split())
solv(a,b)
Code Review
- 수학적 모델링의 현실화: 수식적인 정답을 구하는 것에 그치지 않고,
while c*y <= 1루프를 도입해 실제 세계의 분배 조건($x>0$)을 우아하게 해결한 점이 매우 훌륭함. - 부동소수점 오차 방지: 경계값 검사 시 실수형
1e9대신 완벽한 정수 비교를 위해10**9를 사용하는 것이 안전함.
유사 문제 추천
- 잉여역수 구하기 (BOJ)
- 확장 유클리드 알고리즘 (BOJ)
- 계산기 프로그램 (BOJ)
- 선형 연립 합동식 (BOJ)
- 사과나무 (BOJ)
This post is licensed under CC BY 4.0 by the author.