#include <stdio.h>
#include <stdlib.h>

// 行列の掛け算を行う関数 (C = A * B)
void multiply_matrices(int rows, int cols, double **A, double **B, double **C) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            C[i][j] = 0;
            for (int k = 0; k < cols; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

int main() {
    int rows, cols;

    // 1. 行数と列数の読み込み
    if (scanf("%d %d", &rows, &cols) != 2) return 1;
    printf("指定サイズ: %d行 %d列\n", rows, cols);

    // 2. メモリ確保 (行列A, A^2, A^3 用の3つを用意)
    double **A = (double **)malloc(rows * sizeof(double *));
    double **A2 = (double **)malloc(rows * sizeof(double *));
    double **A3 = (double **)malloc(rows * sizeof(double *));
    for (int i = 0; i < rows; i++) {
        A[i] = (double *)malloc(cols * sizeof(double));
        A2[i] = (double *)malloc(cols * sizeof(double));
        A3[i] = (double *)malloc(cols * sizeof(double));
    }

    // 3. 各要素に数値を読み込む
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (scanf("%lf", &A[i][j]) != 1) return 1;
        }
    }

    // 4. 【一つ目の課題】入力された2次元配列を表示
    printf("\n--- 入力された2次元配列 (行列A) ---\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%g\t", A[i][j]);
        }
        printf("\n");
    }

    // 5. 【二つ目の課題】行列の3乗を計算
    // A^2 = A * A
    multiply_matrices(rows, cols, A, A, A2);
    // A^3 = A^2 * A
    multiply_matrices(rows, cols, A2, A, A3);

    // 6. 計算結果 (A^3) の表示
    printf("\n--- 行列の3乗 (A^3) の計算結果 ---\n");
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%g\t", A3[i][j]);
        }
        printf("\n");
    }

    // 7. メモリ解放
    for (int i = 0; i < rows; i++) {
        free(A[i]); free(A2[i]); free(A3[i]);
    }
    free(A); free(A2); free(A3);

    return 0;
}