문제
자연수 A를 B번 곱한 수를 알고 싶다. 단 구하려는 수가 매우 커질 수 있으므로 이를 C로 나눈 나머지를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 모두 2,147,483,647 이하의 자연수이다.
출력
첫째 줄에 A를 B번 곱한 수를 C로 나눈 나머지를 출력한다.
내가 푼 풀이
접근방법: 수학, 분할정복
이 문제는 지수법칙과 모듈러연산의 분배법칙을 알고있다면 풀 수있다.
본인은 몰라서 검색을 통해 알게되었다..
지수법칙: $x^{ab} = x^{a} \times x^{b}$
모듈러연산의 분배법칙:$(A\times B)\mathrm{mod}C = (A \mathrm{mod}C\times B\mathrm{mod}C)\mathrm{mod}C$
분할: 지수법칙 이용
$m = B / 2$
B가 짝수: $A^{C} = A^{m} \times A^{m} $
B가 홀수:$A^{C} = A^{m} \times A^{m+1} $
정복: 분배법칙 이용
$ B \doteq 1 $ $\mathrm{return} $ $A\div C $
$B\neq 1$ $((A^{m} \div C) \times (A^{m}\div C)) \div C $ , $((A^{m} \div C) \times (A^{m+1}\div C)) \div C $
B가 1이 아니라면 두가지 경우의 수가 있다.(홀수, 짝수)
이렇게 m이 1이될때까지 분할후 m이 1이되면 정복과정을 진행하여 결과를 도출한다.
직관적으로 코드를 짰다가 함수 재귀호출을 너무많이하여 시간초과가 났다.
<시간초과>
// 시간초과
func mul2(_ n: Int,_ c: Int,_ d: Int) -> Int {
if c == 1 { return n%d}
let m = c/2
if c % 2 == 0{
return (mul(n, m, d)%d * mul(n, m, d)%d)%d
} else {
return (mul(n, m, d)%d * mul(n, m+1, d)%d)%d
}
}
<수정한 코드>
import Foundation
// 입력
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
var A = input[0], B = input[1], C = input[2]
// 분할 정복
func mul(_ n: Int,_ c: Int,_ d: Int) -> Int {
// c가 1이될때까지 분할하고, 1이됬다면 정복과정을 진행한다.
if c == 1 { return n%d}
// 지수법칙을 이용하여 c/2번 곱한 나머지를 구한다.
let m = mul(n, c/2, d)
// c가 짝수라면 곱해주고,
// c가 홀수라면 c = 5 -> n^2 * n^2 * n^1
// n을 한번곱한 나머지를 추가로 곱해준다.(분배법칙)
if c % 2 == 0{
return m*m%d
} else {
return m*m%d*n%d
}
}
print(mul(A, B, C))
'코딩테스트 > 백준' 카테고리의 다른 글
BOJ-10830 행렬 제곱 Swift (0) | 2024.05.05 |
---|---|
BOJ-11401 이항 계수 3 Swift (0) | 2024.05.03 |
BOJ-1780 종이의 개수 Swift (0) | 2024.05.03 |
BOJ-1992 쿼드트리 Swift (0) | 2024.05.03 |
BOJ-10986 나머지 합 Swift (1) | 2024.05.02 |