import java.io.*;
import java.util.Arrays;

/**
 * Solution for NEERC'2013 Problem A: ASCII Puzzle.
 * This solution checks correctness of the input.
 *
 * @author Roman Elizarov
 */
public class ascii_re {

    public static void main(String[] args) throws Exception {
        new ascii_re().go();
    }

    void go() throws Exception {
        long time = System.currentTimeMillis();
        read();
        solve();
        write();
        System.out.printf("Done in %d ms, countRec=%d%n", System.currentTimeMillis() - time, countRec);
    }

    int k;
    int w;
    int h;
    char[][][] p;

    int mx;
    int my;

    int l;
    int r;
    int t;
    int b;

    void read() throws Exception {
        Scanner in = new Scanner(new File("ascii.in"));
        k = in.nextInt();
        w = in.nextInt();
        h = in.nextInt();
        in.nextLine();
        assert k >= 1 && k <= 16;
        assert w >= 3 && w <= 5;
        assert h >= 3 && h <= 5;
        mx = 3 * w - 2;
        my = 3 * h - 2;
        p = new char[k][mx][my];
        l = w - 1;
        r = 2*w - 2;
        t = h - 1;
        b = 2*h - 2;
        for (int i = 0; i < k; i++) {
            if (i > 0)
                in.nextLine();
            char pc = (char)('A' + i);
            for (int y = 0; y < my; y++) {
                String s = in.next();
                in.nextLine();
                assert s.length() == mx;
                for (int x = 0; x < mx; x++) {
                    char c = s.charAt(x);
                    assert c == '.' || c == pc;
                    p[i][x][y] = c;
                }
            }
            assert p[i][l][t] == pc;
            assert p[i][r][t] == pc;
            assert p[i][l][b] == pc;
            assert p[i][r][b] == pc;
        }
        in.close();
    }

    static final int L = 0;
    static final int R = 1;
    static final int T = 2;
    static final int B = 3;

    boolean[][] br;  // border
    boolean[][] rt;  // right neighbour
    boolean[][] dn;  // down neighbour

    int n;
    int m;

    int W;
    int H;
    char[][] paper;

    int[][] a;
    boolean[] u;

    void solve() {
        // compute bf
        int[] cnt = new int[4];
        br = new boolean[k][4];
        for (int i = 0; i < k; i++) {
            Arrays.fill(br[i], true);
            for (int x = 0; x < mx; x++) {
                boolean lf = x < l;
                boolean rf = x > r;
                for (int y = 0; y < my; y++) {
                    boolean tf = y < t;
                    boolean bf = y > b;
                    char c = p[i][x][y];
                    if (c == '.') {
                        if (x == l && !tf && !bf) br[i][L] = false;
                        if (x == r && !tf && !bf) br[i][R] = false;
                        if (y == t && !lf && !rf) br[i][T] = false;
                        if (y == b && !lf && !rf) br[i][B] = false;
                    } else {
                        assert !((lf || rf) && (y <= t || y >= b));
                        assert !((tf || bf) && (x <= l || x >= r));
                        if (lf) br[i][L] = false;
                        if (rf) br[i][R] = false;
                        if (tf) br[i][T] = false;
                        if (bf) br[i][B] = false;
                    }
                }
            }
            for (int j = 0; j < 4; j++)
                if (br[i][j])
                    cnt[j]++;
        }
        assert cnt[L] == cnt[R] && cnt[T] == cnt[B];
        n = cnt[T];
        m = cnt[L];
        assert n == m;
        assert k == n * m;
        // allocate paper
        W = w * n;
        H = h * m;
        paper = new char[W][H];
        for (char[] chars : paper)
            Arrays.fill(chars, '.');
        // compute rt and dn
        rt = new boolean[k][k];
        dn = new boolean[k][k];
        for (int i = 0; i < k; i++) {
            int x0 = br[i][L] ? 0 : 1;
            int y0 = br[i][T] ? 0 : 1;
            boolean ok = place(i, x0, y0, false);
            assert ok; // consistency check
            assert paperConnected((char)(i + 'A')); // well-formedness test
            assert paperWithoutHoles(); // well-formedness test
            for (int j = 0; j < k; j++) {
                if (i == j)
                    continue;
                // rt
                boolean pj = place(j, x0 + 1, y0, false);
                rt[i][j] = pj && paperWithoutHoles();
                boolean uj = place(j, x0 + 1, y0, true);
                assert uj == pj;
                // dn
                pj = place(j, x0, y0 + 1, false);
                dn[i][j] = pj && paperWithoutHoles();
                uj = place(j, x0, y0 + 1, true);
                assert uj == pj;
            }
            ok = place(i, x0, y0, true);
            assert ok;
        }

        // build answer
        a = new int[n][m];
        u = new boolean[k];
        boolean ok = solve(0, 0);
        assert ok;
        // place answer
        for (int x = 0; x < n; x++)
            for (int y = 0; y < m; y++) {
                ok = place(a[x][y], x, y, false);
                assert ok;
            }
    }

    private boolean place(int i, int x, int y, boolean undo) {
        for (int x0 = 0; x0 < mx; x0++)
            for (int y0 = 0; y0 < my; y0++) {
                char c = p[i][x0][y0];
                if (c != '.') {
                    int px = x * w + x0 - l;
                    int py = y * h + y0 - t;
                    if (px < 0 || px >= W || py < 0 || py >= H)
                        return false;
                    if (undo) {
                        if (paper[px][py] != c)
                            return false;
                        paper[px][py] = '.';
                    } else {
                        if (paper[px][py] != '.')
                            return false;
                        paper[px][py] = c;
                    }
                }
            }
        return true;
    }

    private boolean paperWithoutHoles() {
        boolean ok = true;
    loop:
        for (int px = 0; px < W; px++)
            for (int py = 0; py < H; py++)
                if (paper[px][py] == '.') {
                    if (!markPaper(px, py, '.', '*')) {
                        ok = false; // hole
                        break loop;
                    }
                }
        unMarkPaper('.', '*');
        return ok;
    }

    private boolean paperConnected(char c) {
        boolean ok = true;
        boolean marked = false;
    loop:
        for (int px = 0; px < W; px++)
            for (int py = 0; py < H; py++)
                if (paper[px][py] == c) {
                    if (marked) {
                        ok = false; // second component !
                        break loop;
                    }
                    markPaper(px, py, c, '+');
                    marked = true;
                }
        assert marked;
        unMarkPaper(c, '+');
        return ok;
    }

    private boolean markPaper(int px, int py, char cFrom, char cTo) {
        if (px < 0 || px >= W || py < 0 || py >= H)
            return true; // border seen
        if (paper[px][py] != cFrom)
            return false; // already marked or occupied
        paper[px][py] = cTo;
        boolean borderSeen = markPaper(px - 1, py, cFrom, cTo);
        borderSeen |= markPaper(px + 1, py, cFrom, cTo);
        borderSeen |= markPaper(px, py - 1, cFrom, cTo);
        borderSeen |= markPaper(px, py + 1, cFrom, cTo);
        return borderSeen;
    }

    private void unMarkPaper(char cFrom, char cTo) {
        for (int px = 0; px < W; px++)
            for (int py = 0; py < H; py++)
                if (paper[px][py] == cTo)
                    paper[px][py] = cFrom;
    }

    int countRec;

    private boolean solve(int x, int y) {
        countRec++;
        if (x == n) {
            x = 0;
            y++;
        }
        if (y == m)
            return true;
        for (int i = 0; i < k; i++)
            if (!u[i]) {
                if (x == 0 && !br[i][L]) continue;
                if (x == n - 1 && !br[i][R]) continue;
                if (y == 0 && !br[i][T]) continue;
                if (y == m - 1 && !br[i][B]) continue;
                if (x > 0 && !rt[a[x - 1][y]][i]) continue;
                if (y > 0 && !dn[a[x][y - 1]][i]) continue;
                u[i] = true;
                a[x][y] = i;
                if (solve(x + 1, y))
                    return true;
                u[i] = false;
            }
        return false;
    }

    void write() throws Exception {
        PrintWriter out = new PrintWriter("ascii.out");
        out.println(W + " " + H);
        for (int py = 0; py < H; py++) {
            for (int px = 0; px < W; px++)
                out.print(paper[px][py]);
            out.println();
        }
        out.close();
    }

//----------------- just for validation ------------------

    /**
     * Strict scanner to verify 100% correspondence between input files and input file format specification.
     * It is a drop-in replacement for {@link java.util.Scanner} that could be added to a solution source
     * (cut-and-paste) without breaking its ability to work with {@link java.util.Scanner}.
     */
    public class Scanner {
        private final BufferedReader in;
        private String line = "";
        private int pos;
        private int lineNo;

        public Scanner(File source) throws FileNotFoundException {
            in = new BufferedReader(new FileReader(source));
            nextLine();
        }

        public void close() {
            assert line == null : "Extra data at the end of file";
            try {
                in.close();
            } catch (IOException e) {
                throw new AssertionError("Failed to close with " + e);
            }
        }

        public void nextLine() {
            assert line != null : "EOF";
            assert pos == line.length() : "Extra characters on line " + lineNo;
            try {
                line = in.readLine();
            } catch (IOException e) {
                throw new AssertionError("Failed to read line with " + e);
            }
            pos = 0;
            lineNo++;
        }

        public String next() {
            assert line != null : "EOF";
            assert line.length() > 0 : "Empty line " + lineNo;
            if (pos == 0)
                assert line.charAt(0) > ' ' : "Line " + lineNo + " starts with whitespace";
            else {
                assert pos < line.length() : "Line " + lineNo + " is over";
                assert line.charAt(pos) == ' ' : "Wrong whitespace on line " + lineNo;
                pos++;
                assert pos < line.length() : "Line " + lineNo + " is over";
                assert line.charAt(pos) > ' ' : "Line " + lineNo + " has double whitespace";
            }
            StringBuilder sb = new StringBuilder();
            while (pos < line.length() && line.charAt(pos) > ' ')
                sb.append(line.charAt(pos++));
            return sb.toString();
        }

        public int nextInt() {
            String s = next();
            assert s.length() == 1 || s.charAt(0) != '0' : "Extra leading zero in number " + s + " on line " + lineNo;
            assert s.charAt(0) != '+' : "Extra leading '+' in number " + s + " on line " + lineNo;
            try {
                return Integer.parseInt(s);
            } catch (NumberFormatException e) {
                throw new AssertionError("Malformed number " + s + " on line " + lineNo);
            }
        }
    }
}
