알고리즘/문제 풀이
10830번: 행렬 제곱
Themion
2022. 1. 3. 12:16
https://www.acmicpc.net/problem/10830
10830번: 행렬 제곱
크기가 N*N인 행렬 A가 주어진다. 이때, A의 B제곱을 구하는 프로그램을 작성하시오. 수가 매우 커질 수 있으니, A^B의 각 원소를 1,000으로 나눈 나머지를 출력한다.
www.acmicpc.net
B의 최댓값이 100,000,000,000이므로, A를 B번 곱할 경우 시간 초과가 발생한다. 따라서 B를 2진법으로 보았을 때, n의 자리의 값이 1인 각 n = 2^k에 대해 구하고자 하는 값은 A^(∑n)과 같다.
#include <cstdio>
#define MAX_N 5
#define MOD 1000
#define FOR for (int row = 0; row < N; row++) for (int col = 0; col < N; col++)
// 행렬을 저장할 클래스
class matrix {
public:
// 행렬을 저장할 공간
int mat[MAX_N][MAX_N] = { {0} };
// [] 연산자를 이용해 mat에 접근
int* operator[](int i) { return mat[i]; }
};
// 입력받을 행렬의 크기
int N;
// 두 행렬 P, Q의 곱을 ret에 저장해 반환
matrix operator*(matrix P, matrix Q) {
matrix ret;
FOR for (int i = 0; i < N; i++)
ret[row][col] = (P[row][i] * Q[i][col] + ret[row][col]) % MOD;
return ret;
}
int main() {
// A 행렬을 제곱할 횟수
unsigned long long B;
// A: B제곱할 행렬, ans: A ^ B
matrix A, ans;
// N과 B, A를 차례로 입력받고 ans를 단위행렬로 초기화
scanf("%d %lld", &N, &B);
FOR scanf("%d", A[row] + col);
for (int i = 0; i < MAX_N; i++) ans[i][i] = 1;
// 이진수 B의 각 자리에 대해
do {
// B의 현재 자리가 1일 때 ans에 A를 곱한다
if (B % 2) ans = ans * A;
// 곱셈 수를 절약하기 위해 A를 제곱
A = A * A;
} while (B /= 2);
// ans의 각 성분을 차례로 출력
FOR printf("%d%c", ans[row][col], (col == N - 1 ? '\n' : ' '));
return 0;
}