오늘의 한 마디
이건 알고리즘으로 최적화를 하는 게 아니라 정수론으로 최적화하는 거라... 할 말이 없네요
그냥 개념이라도 익히고 넘어갑시다
자연수 A를 B번 곱한 수를 알고 싶다. 단 구하려는 수가 매우 커질 수 있으므로 이를 C로 나눈 나머지를 구하는 프로그램을 작성하시오.
첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 모두 2,147,483,647 이하의 자연수이다.
첫째 줄에 A를 B번 곱한 수를 C로 나눈 나머지를 출력한다.
10 11 12
4
# A ** B % C
import sys
A, B, C = map(int, sys.stdin.readline().rstrip().split())
print(A ** B % C)
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
당연히 시간 초과.
이 문제의 알고리즘 분류는 분할 정복을 이용한 거듭제곱이다.
분할 정복을 이용하여 A**B
를 구현한 결과는 다음과 같다.
def fpow(A, B):
if B == 1:
return A
x = fpow(A, B//2)
return x*x if B%2 == 0 else x*x*A
솔직히 시간 초과가 되는 이유가 나머지 연산이 아니라 제곱 연산이라고 생각했고,
import sys
A, B, C = map(int, sys.stdin.readline().rstrip().split())
def fpow(A, B):
if B == 1:
return A
x = fpow(A, B//2)
return x**2 if B%2 == 0 else x**2 * A
print(fpow(A, B) % C)
로 제출했으나, 이 풀이 또한 시간 초과였다.
멘붕에 빠졌고,
이 링크의 풀이를 보고 나머지 분배 법칙을 배웠다.
(A*B) % C = (A%C) * (B%C) % C
A와 B를 곱했을 때 수가 무진장 커진다면, 나머지끼리 곱해서 수를 미리 줄여버려도 괜찮다!
나머지 연산을 미리 하지 않고 A**B
를 해버린다면 분할 정복을 통해 구했을지라도
B가 정말로 매우 커지면(이 문제에서는 A, B, C는 모두 2,147,483,647 이하의 자연수였다.)
그 값을 가지고 있는 것만으로도 시간이 오래 걸린다는 걸 이해하는 것이 포인트다.
# A ** B % C
import sys
A, B, C = map(int, sys.stdin.readline().rstrip().split())
def f(A, B, C):
if B == 1:
return A % C
x = f(A, B//2, C)
return x**2 % C if B%2 == 0 else (x**2 % C) * (A%C) % C
print(f(A, B, C))
지수가 홀수일 때는 위의 나머지 분배 법칙을 이용하여 중첩 계산해주었다.