-
[C++] BOJ 1629번: 곱셈프로그래밍/알고리즘 PS 2024. 3. 28. 13:06
학교에서 진행하는 수업에서 적절한 알고리즘 문제를 찾아보고 공유하게 되었다. 가능하면 문제 설명이 간결한 문제를 찾고 싶었고, 백준 사이트에서 적절한 난이도의 문제를 찾게 되었다.
문제 링크
https://www.acmicpc.net/problem/1629
문제 분석
해당 문제는 정답률이 2024년 3월 기준 약 27%로 꽤 낮은 편에 속한다. 이는 문제의 시간 제한이 0.5초여서 생각보다 단순히 접근하면 틀리기 쉬운 문제이기 때문으로 보인다.
예를 들어 문제의 입력 조건과 시간 제한을 확인하지 않고 아래와 같은 코드를 작성하면 '틀렸습니다'가 출력된다.
int main(void) { int A, B, C; cin >> A >> B >> C; // A를 B번 곱하고 C로 나눈 나머지를 출력하는 코드 int result = 1; for(int i=0; i<B; i++) result *= A; result %= C; cout << result << '\n'; return 0; }
이는 A의 B승을 계산하는 과정에서 오버플로우가 발생하고, 입력에 따라 시간이 0.5초를 초과하는 연산이 발생하기 때문이다. 그렇다면 해당 문제를 풀기 위해서는 어떻게 접근해야 할까?
- C++로 문제를 풀 때에는 문제에 주어진 조건에 따라 A의 B제곱을 계산할 때 오버플로우가 발생하지 않도록 주의해야 한다.
int
타입에는 A의 B승을 담지 못할 수 있으므로 8 byte의 정수를 담을 수 있는long long
타입의 사용이 필요하다. - 0.5초 내에 문제를 풀기 위해서는 분할 정복 방식으로 문제를 푸는 것이 필요하다.
문제 풀이
먼저 분할 정복 방식을 어떻게 적용할지 이야기해보자. 해당 문제는 A의 B승을 빠르게 계산하는 게 중요하다. A의 B승을
A^B
라고 표현하기로 하자.A^B
에 대해서 다음 식이 성립한다.- B가 짝수인 경우
A^B = A^(B / 2) * A^(B / 2)
- B가 홀수인 경우
A^B = A^(B / 2) * A^(B / 2) * A
이 때/
연산자는 나누기에 대한 몫 연산자이다.
위 식대로
A, B, C
를 파라미터로 전달받아A^B
을C
로 나눈 나머지 값을 계산하는 함수를 작성해 보자.long long solution(int A, int B, int C) { if (B == 0) return 1; long long result = (solution(A, B / 2, C) * solution(A, B / 2, C)) % C; if (B % 2 == 1) result = (result * A) % C; return result; }
이 때, 위의 코드에서
solution(A, B / 2, C) * solution(A, B / 2, C)
을 계산할 때 같은 값에 대해 2번 계산하는 문제가 발생한다. 이 문제를 해결하기 위해 함수를 다음과 같이 변경한다.long long solution(int A, int B, int C) { if (B == 0) return 1; long long result = solution(A, B / 2, C); result = (result * result) % C; if (B % 2 == 1) result = (result * A) % C; return result; }
result
변수에solution(A, B / 2, C)
값을 담아주고result = (result * result) % C
를 통해 중복되는 값을 2번 계산하는 문제를 해결하였다.전체 코드
전체 코드는 다음과 같다.
#include <iostream> using namespace std; long long solution(int A, int B, int C) { if (B == 0) return 1; long long result = solution(A, B / 2, C); result = (result * result) % C; if (B % 2 == 1) result = (result * A) % C; return result; } int main(void) { ios::sync_with_stdio(false); cin.tie(nullptr); int A, B, C; cin >> A >> B >> C; cout << solution(A, B, C) << '\n'; return 0; }
결과
풀 때마다 틀리는 문제이다. 볼 때마다 새롭다...
그 외
A, B, C = map(int, input().split()) print(pow(A, B, C))
역시 없는 게 없다는 파이썬. 이 문제를 두 줄만에 해결할 수 있다...
'프로그래밍 > 알고리즘 PS' 카테고리의 다른 글
[C++] BOJ 1748번: 수 이어 쓰기 1 (0) 2024.03.28 [C++] BOJ 9506번: 약수들의 합 (0) 2024.03.28 [C++] BOJ 1699번: 제곱수의 합 (0) 2020.12.08 [C++] BOJ 2579번: 계단 오르기 (0) 2020.12.08 [C++] BOJ 1912번: 연속합 (0) 2020.12.01 - C++로 문제를 풀 때에는 문제에 주어진 조건에 따라 A의 B제곱을 계산할 때 오버플로우가 발생하지 않도록 주의해야 한다.