Skip to main content Link Menu Expand (external link) Document Search Copy Copied

10830번 행렬 제곱

Problem link: https://www.acmicpc.net/problem/10830

Keywords: Divide and conquer

(1) 자존감 올리려고, (2) daily todo 에서 한 줄 빠르게 지우려고 풀었다. 분할정복으로 풀어주면 된다.

아래는 솔루션이다.

#include <cstdint>
#include <iostream>
#include <vector>

using Mat1D = std::vector<std::int64_t>;
using Mat2D = std::vector<Mat1D>;

int N;
std::int64_t B;
Mat2D A;
Mat2D EYE;
constexpr int kR(1000);

Mat2D Multiply(const Mat2D& mat0, const Mat2D& mat1) {
  Mat2D ret(N, Mat1D(N, 0));
  for (std::size_t r{0}; r < mat0.size(); ++r) {
    for (std::size_t c{0}; c < mat0[r].size(); ++c) {
      for (std::size_t i{0}; i < mat0[r].size(); ++i) {
        ret[r][c] += mat0[r][i] * mat1[i][c];
        ret[r][c] %= kR;
      }
    }
  }
  return ret;
}

Mat2D Solve(std::int64_t exponent) {
  if (exponent == 0) {
    return EYE;
  } else {
    auto half{Solve(exponent / 2)};
    auto half_sq{Multiply(half, half)};
    return exponent % 2 ? Multiply(half_sq, A) : half_sq;
  }
}

int main(void) {
  // For faster IO.
  std::ios_base::sync_with_stdio(false);
  std::cout.tie(nullptr);
  std::cin.tie(nullptr);

  // Read inputs.
  std::cin >> N >> B;
  A.assign(N, Mat1D(N, 0));
  for (auto r{0}; r < N; ++r) {
    for (auto c{0}; c < N; ++c) {
      std::cin >> A[r][c];
    }
  }

  // Solve.
  EYE.assign(N, Mat1D(N, 0));
  for (auto r{0}; r < N; ++r) {
    EYE[r][r] = 1;
  }
  auto answer{Solve(B)};
  for (auto r{0}; r < N; ++r) {
    for (auto c{0}; c < N; ++c) {
      std::cout << answer[r][c] << ' ';
    }
    std::cout << "\n";
  }

  return 0;
}