import java.io.File;
import java.io.PrintWriter;
import java.util.*;

public class ascii_gk {
    static Scanner in;
    static PrintWriter out;
    private int n;
    private boolean[][] below;
    private boolean[][] aside;
    private int tw;
    private int th;

    void run() {
        n = in.nextInt();
        int w = in.nextInt();
        int h = in.nextInt();

        char[][][] pieces = new char[n + 1][h * 3 - 2][];
        for (int i = 0; i < n; i++) {
            for (int r = 0; r < h * 3 - 2; r++) {
                pieces[i][r] = in.next().toCharArray();
                assert pieces[i][r].length == w * 3 - 2;
            }
        }

        for (int r = 0; r < h * 3 - 2; r++) {
            pieces[n][r] = new char[w * 3 - 2];
            Arrays.fill(pieces[n][r], '.');
        }

        for (int r = h - 1; r < 2 * h - 1; r++) {
            for (int c = w - 1; c < 2 * w - 1; c++) {
                pieces[n][r][c] = '@';
            }
        }

        below = new boolean[n + 1][n + 1];
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                below[i][j] = true;
                char[][] block = new char[4 * h][3 * w];
                for (int r = 0; r < 3 * h - 2; r++) {
                    for (int c = 0; c < 3 * w - 2; c++) {
                        if (pieces[i][r][c] != '.') {
                            block[r + 1][c + 1] = '%';
                        }
                        if (pieces[j][r][c] != '.') {
                            block[r + h + 1][c + 1] = '%';
                        }
                    }
                }
                for (int r = h; r < 3 * h - 2; r++) {
                    for (int c = w; c < 2 * w - 2; c++) {
                        below[i][j] &= pieces[i][r][c] == '.' || pieces[j][r - h][c] == '.';
                    }
                }
                below[i][j] &= singleConnected(block);
            }
        }

        aside = new boolean[n + 1][n + 1];
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                aside[i][j] = true;
                char[][] block = new char[3 * h][4 * w];
                for (int r = 0; r < 3 * h - 2; r++) {
                    for (int c = 0; c < 3 * w - 2; c++) {
                        if (pieces[i][r][c] != '.') {
                            block[r + 1][c + 1] = '%';
                        }
                        if (pieces[j][r][c] != '.') {
                            block[r + 1][c + w + 1] = '%';
                        }
                    }
                }
                for (int r = h; r < 2 * h - 2; r++) {
                    for (int c = w; c < 3 * w - 2; c++) {
                        aside[i][j] &= pieces[i][r][c] == '.' || pieces[j][r][c - w] == '.';
                    }
                }
                aside[i][j] &= singleConnected(block);
            }
        }

        for (int i = 0; i < n; i++) {
            if (aside[i][n]) {
                th++;
            }
            if (below[i][n]) {
                tw++;
            }
        }
        use = new boolean[n];
        field = new int[th][tw];
        solve(0, 0);
        char[][] answer = new char[h * th][w * tw];
        for (int i = 0; i < h * th; i++) {
            answer[i] = new char[w * tw];
        }
        for (int tr = 0; tr < th; tr++) {
            for (int tc = 0; tc < tw; tc++) {
                int i = field[tr][tc];
                for (int r = 0; r < 3 * h - 2; r++) {
                    for (int c = 0; c < 3 * w - 2; c++) {
                        if (pieces[i][r][c] != '.') {
                            answer[tr * h + r - h + 1][tc * w + c - w + 1] = pieces[i][r][c];
                        }
                    }
                }
            }
        }
        out.println(w * tw + " " + h * th);
        for (char[] chars : answer) {
            out.println(chars);
        }
    }

    boolean[] use;
    int[][] field;
    boolean solve(int r, int c) {
        if (r == th) {
            return true;
        }
        int above = r == 0 ? n : field[r - 1][c];
        int left = c == 0 ? n : field[r][c - 1];
        for (int i = 0; i < n; i++) {
            if (!use[i] && below[above][i] && aside[left][i]) {
                if ((r != th - 1 || below[i][n]) && (c != tw - 1 || aside[i][n])) {
                    field[r][c] = i;
                    use[i] = true;
                    if (solve(r + (c + 1) / tw, (c + 1) % tw)) {
                        return true;
                    }
                    use[i] = false;
                }
            }
        }
        return false;
    }

    private boolean singleConnected(char[][] block) {
        fill(0, 0, block);
        for (char[] row : block) {
            for (char c : row) {
                if (c != '%') {
                    return false;
                }
            }
        }
        return true;
    }

    int[] dx = new int[]{0, 1, 0, -1};
    int[] dy = new int[]{1, 0, -1, 0};

    private void fill(int r, int c, char[][] block) {
        if (r < 0 || block.length <= r || c < 0 || block[r].length <= c || block[r][c] == '%') {
            return;
        }
        block[r][c] = '%';
        for (int i = 0; i < 4; i++) {
            fill(r + dy[i], c + dx[i], block);
        }
    }

    public static void main(String[] args) throws Exception {
        in = new Scanner(new File("ascii.in"));
        out = new PrintWriter("ascii.out");

        new ascii_gk().run();

        in.close();
        out.close();
    }
}
