https://www.acmicpc.net/problem/1629

 

1629번: 곱셈

첫째 줄에 A, B, C가 빈 칸을 사이에 두고 순서대로 주어진다. A, B, C는 모두 2,147,483,647 이하의 자연수이다.

www.acmicpc.net

 

1. 핵심 아이디어

분할정복을 이용한 거듭제곱 문제

 

A^10은 A*A*A*A*A*A*A*A*A*A로 곱하기연산을 총 9번 반복해야한다.

 

이걸 분할정복하기 위해

(A^2)^5로 바꾸면 A^2계산 1번, 그 후 제곱연산을 위한 4번의 계산으로 5번으로 줄어든다.

여기서 A^2를 A`라고 부른다면 (A`)^5가 되는데 이건 A` * (A`)^4와 같다.

그럼 또 (A`)^4를 (A`^2)^2로 분할정복 가능하다.

 

즉 정리하자면

지수가 짝수라면 (A^(지수/2))^2

지수가 홀수라면 A * (A^(지수/2))^2

 

2. 코드구현

1) 재귀방식으로 구현

#include <bits/stdc++.h>
using namespace std;

int A, B, C;
int recursion(int B)
{
	if (B == 0) return 1;

	long long temp = recursion(B / 2);
	temp = (temp * temp) % C;

	if (B % 2 == 0) return temp;
	else return (A * temp) % C;
}

int main()
{
	ios::sync_with_stdio(false); cin.tie(NULL);

	cin >> A >> B >> C;
	cout << recursion(B);
	
	return 0;
}

B의 0승은 1로 return

B의 1승부터는 (A * temp) % C로 나머지연산으로 값 줄여가면서 분할정복

 

2) 반복문으로 구현

#include <bits/stdc++.h>
using namespace std;

int main()
{
	ios::sync_with_stdio(false); cin.tie(NULL);

	long long A, B, C;
	cin >> A >> B >> C;

	long long answer = 1;
	while (B > 0) {
		if (B & 1) answer = (answer * A) % C; // 남는 한번 미리 곱해두고

		A = (A * A) % C;
		B /= 2; // A ^ 2로 만들면서 B는 반으로 줄임
	}

	cout << answer;

	return 0;
}