public int[][] divideNConquer(final int[][] X, final int[][] Y) {
        try {
            int half = X.length / 2;
            int full = X.length;
            int[][] result = new int[full][full];

            if (full == 2) {
                result[0][0] = X[0][0] * Y[0][0] + X[0][1] * Y[1][0];
                result[0][1] = X[0][0] * Y[0][1] + X[0][1] * Y[1][1];
                result[1][0] = X[1][0] * Y[0][0] + X[1][1] * Y[1][0];
                result[1][1] = X[1][0] * Y[0][1] + X[1][1] * Y[1][1];
            } else {
                // create sub matrices
                int[][] X00 = initSubMatrix(X, 0, half, 0, half);
                int[][] X01 = initSubMatrix(X, 0, half, half, full);
                int[][] X10 = initSubMatrix(X, half, full, 0, half);
                int[][] X11 = initSubMatrix(X, half, full, half, full);
                int[][] Y00 = initSubMatrix(Y, 0, half, 0, half);
                int[][] Y01 = initSubMatrix(Y, 0, half, half, full);
                int[][] Y10 = initSubMatrix(Y, half, full, 0, half);
                int[][] Y11 = initSubMatrix(Y, half, full, half, full);

                // sub matrices multiplication
                int[][] C00 = addMatrix(divideNConquer(X00, Y00), divideNConquer(X01, Y10));
                int[][] C01 = addMatrix(divideNConquer(X00, Y01), divideNConquer(X01, Y11));
                int[][] C10 = addMatrix(divideNConquer(X10, Y00), divideNConquer(X11, Y10));
                int[][] C11 = addMatrix(divideNConquer(X10, Y01), divideNConquer(X11, Y11));

                // merge back to original matrix
                copyBack(result, 0, half, 0, half, C00);
                copyBack(result, 0, half, half, full, C01);
                copyBack(result, half, full, 0, half, C10);
                copyBack(result, half, full, half, full, C11);
            }

            return result;
        } catch (NullPointerException e) {
            e.printStackTrace();

            return null;
        }
    }