#include using namespace std; using i64 = long long; using i128 = __int128_t; static const int THRESH = 64; // порог для обычного умножения // печать i64 inline void print_i64(i64 x) { cout << x; } // обычное умножение n×n (с безопасной суммой) vector> mul_naive(const vector>& A, const vector>& B) { int n = (int)A.size(); vector> C(n, vector(n, 0)); for (int i = 0; i < n; ++i) { for (int k = 0; k < n; ++k) { i64 aik = A[i][k]; for (int j = 0; j < n; ++j) { // аккумулируем в 128 битах и приводим назад к i64 i128 cur = (i128)aik * (i128)B[k][j] + (i128)C[i][j]; C[i][j] = (i64)cur; } } } return C; } vector> add(const vector>& A, const vector>& B) { int n = (int)A.size(); vector> C(n, vector(n)); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) C[i][j] = A[i][j] + B[i][j]; return C; } vector> sub(const vector>& A, const vector>& B) { int n = (int)A.size(); vector> C(n, vector(n)); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) C[i][j] = A[i][j] - B[i][j]; return C; } vector> strassen(const vector>& A, const vector>& B) { int n = (int)A.size(); if (n <= THRESH) return mul_naive(A, B); int h = n / 2; // разбиение на кварталы vector> A11(h, vector(h)), A12(h, vector(h)), A21(h, vector(h)), A22(h, vector(h)); vector> B11(h, vector(h)), B12(h, vector(h)), B21(h, vector(h)), B22(h, vector(h)); for (int i = 0; i < h; ++i) { for (int j = 0; j < h; ++j) { A11[i][j] = A[i][j]; A12[i][j] = A[i][j + h]; A21[i][j] = A[i + h][j]; A22[i][j] = A[i + h][j + h]; B11[i][j] = B[i][j]; B12[i][j] = B[i][j + h]; B21[i][j] = B[i + h][j]; B22[i][j] = B[i + h][j + h]; } } // Классическая нумерация M1..M7 auto M1 = strassen(add(A11, A22), add(B11, B22)); auto M2 = strassen(add(A21, A22), B11); auto M3 = strassen(A11, sub(B12, B22)); auto M4 = strassen(A22, sub(B21, B11)); auto M5 = strassen(add(A11, A12), B22); auto M6 = strassen(sub(A21, A11), add(B11, B12)); auto M7 = strassen(sub(A12, A22), add(B21, B22)); // Сборка блоков результата auto C11 = sub(add(M1, M4), add(M5, vector>(h, vector(h, 0)))); for (int i = 0; i < h; ++i) // C11 = M1 + M4 - M5 + M7 for (int j = 0; j < h; ++j) C11[i][j] += M7[i][j]; auto C12 = add(M3, M5); // C12 = M3 + M5 auto C21 = add(M2, M4); // C21 = M2 + M4 auto C22 = add(sub(M1, M2), add(M3, M6)); // C22 = M1 - M2 + M3 + M6 // склейка vector> C(n, vector(n)); for (int i = 0; i < h; ++i) { for (int j = 0; j < h; ++j) { C[i][j] = C11[i][j]; C[i][j + h] = C12[i][j]; C[i + h][j] = C21[i][j]; C[i + h][j + h] = C22[i][j]; } } return C; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; if (!(cin >> n)) return 0; vector> A(n, vector(n)); vector> B(n, vector(n)); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) cin >> A[i][j]; for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) cin >> B[i][j]; auto C = strassen(A, B); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (j) cout << ' '; print_i64(C[i][j]); } cout << '\n'; } return 0; }