A를 B번 곱할 때, B가 최대 2,147,483,647이므로, 2,147,483,647번 곱하면 연산 비용이 너무 많이 든다.
즉, O(B)의 비용이 든다.
하지만 분할 정복을 이용하면, O(logB)로 해결 가능하다.
만약 A를 100번 곱해야 한다고 생각해보자.
A100 = A50 * A50
A50 = A25 * A25
A25 = A12 * A13
A12 = A6 * A6
A13 = A6 * A7
A6 = A3 * A3
A7 = A3 * A4
A3 = A * A2
A4 = A2 * A2
A2 = A * A
따라서, 재귀 함수를 이용해 답을 (log100)번만에 찾을 수 있다.
typedef unsigned long long int ull;
ull multiply(ull a, ull b)
{
if (b == 0) return 1;
else if (b == 1) return a % C;
else if (b & 1) return (a * multiply(a, b - 1)) % C;
else
{
ull tmp = multiply(a, b / 2);
return (tmp * tmp) % C;
}
}
A0은 1이므로, 1을 return하고, A1은 A이므로 A를 return한다.
곱해야하는 수 B가 홀수라면 B = 1 + (B - 1)[짝수]이므로 A * A(B - 1)을 한다.
그렇지 않다면 짝수이므로 절반으로 나누고 곱하면 된다.
실제 문제에서는 나머지를 한 값을 원하므로
(A * B) mod C = (A mod C * B mod C) mod C 공식을 이용하면 된다.
즉, 매번 곱할 때 마다 나머지 연산을 해주면 된다.
재귀 함수말고도 이진수를 이용하면 문제를 해결할 수 있다.
100은 이진법으로 나타내면 (0110 0100)2 = 22 + 25 + 26 = 4 + 32 + 64 = 100 이다.
따라서 A를 100번 곱한다는 것은, (ans = 1로 시작)
B = 100, 짝수 | (0110 0100)2 | A * A = A2 | |
B = 50, 짝수 | (0110 010)2 | A2 * A2 = A4 | |
B = 25, 홀수 | (0110 01)2 | ans = ans * A4 = 1 * A4로 저장. | A4 * A4 = A8 |
B = 12, 짝수 | (0110 0)2 | A8 * A8 = A16 | |
B = 6, 짝수 | (0110)2 | A16 * A16 = A32 | |
B = 3, 홀수 | (011)2 | ans = ans * A32 = A4 * A32 = A36으로 저장. | A32 * A32 = A64 |
B = 1, 홀수 | (01)2 | ans = ans * A64 = A36 * A64 = A100으로 저장. | A64 * A64 = A128 |
B = 0 | 종료 |
이다.
즉, B를 계속 나눠가면서 B가 홀수인 경우 제곱되는 A의 값을 ans에 곱해주면 된다.
두 방법 모두 아래의 코드를 참고하자.
#include <stdio.h>
typedef unsigned long long int ull;
ull A, B, C;
ull multiply(ull a, ull b)
{
if (b == 0) return 1;
else if (b == 1) return a % C;
else if (b & 1) return (a * multiply(a, b - 1)) % C;
else
{
ull tmp = multiply(a, b / 2);
return (tmp * tmp) % C;
}
}
int main(void)
{
ull ans;
ull mul;
scanf("%lld %lld %lld", &A, &B, &C);
/*
printf("%lld\n", multiply(A, B) % C);
return 0;
*/
mul = A;
ans = 1LL;
while (B > 0)
{
if (B % 2 == 1) ans = (ans % C) * (mul % C);
mul = (mul % C) * (mul % C);
B /= 2;
}
printf("%d\n", ans % C);
return 0;
}
'알고리즘 > BAEKJOON' 카테고리의 다른 글
BOJ 2467, 2470 : 두 용액 (0) | 2021.03.29 |
---|---|
BOJ 10830 : 행렬 제곱 (0) | 2021.03.25 |
BOJ 2696 : 중앙값 구하기 (0) | 2021.03.20 |
BOJ 4913 : 페르마의 크리스마스 정리 (0) | 2021.03.19 |
BOJ 7569 : 토마토 (3차원) (0) | 2021.03.17 |
댓글