import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class prog { private static int[] tx = { -1, 1, 0, 0 }; private static int[] ty = { 0, 0, -1, 1 }; public static void main(String[] args) throws java.lang.Exception { long start = System.currentTimeMillis(); BufferedReader bi = new BufferedReader(new InputStreamReader(System.in)); // BufferedReader bi = new BufferedReader(new FileReader("input3.txt")); Integer type = Integer.parseInt(bi.readLine()); String[] dims = bi.readLine().split(" "); Integer m = Integer.parseInt(dims[0]); Integer n = Integer.parseInt(dims[1]); String line; WeightedQuickUnionUF uf = new WeightedQuickUnionUF(n * m); char[][] matrix = new char[m][n]; boolean[][] vis = new boolean[m][n]; int i = 0; while ((line = bi.readLine()) != null){ for (int j = 0; j < n; j++) { matrix[i][j] = line.charAt(j); } i++; } List margins = new ArrayList(); // System.out.println("Reading: " + (System.currentTimeMillis() - start)); for (i = 0; i < m; i++) { for (int j = 0; j < n; j++) { int similarNeighbors = 0; int coord = get1DCoord(i, j, n); for (int k = 0; k < 4; k++) { int x = i + tx[k]; int y = j + ty[k]; if (x >= 0 && x < m && y >= 0 && y < n) { if (matrix[i][j] == matrix[x][y]) { if (!uf.connected(coord, x * n + y)) { uf.union(coord, x * n + y); } similarNeighbors++; } } else { similarNeighbors++; } } if (similarNeighbors < 4) { margins.add(get1DCoord(i, j, n)); } } } // System.out.println("Finished uf: "+(System.currentTimeMillis() - start)); int maxSize = uf.getMaxSize(); if (type == 1) { System.out.print(maxSize); } else { if (maxSize == n * m) { System.out.println(1 + " " + 1); System.out.print(matrix[0][0]); } else { int x = 0; int y = 0; int xLastResort = -1; int yLastResort = 0; char ch = 'a'; char chLastResort = 'a'; for (int k = 0; k < margins.size(); k++) { Integer margin = margins.get(k); int[] coord2D = get2DCoord(margin, n); Map> matchingNeighbours = new HashMap>(); char currentChar = matrix[coord2D[0]][coord2D[1]]; for (int l = 0; l < 4; l++) { int x1 = coord2D[0] + tx[l]; int y1 = coord2D[1] + ty[l]; if (x1 >= 0 && x1 < m && y1 >= 0 && y1 < n) { processNeighbor(n, matrix, new int[] { x1, y1 }, matchingNeighbours, currentChar); } } for (Entry> entry : matchingNeighbours.entrySet()) { Character key = entry.getKey(); List value = entry.getValue(); if (xLastResort == -1) { int[] coord2DLS = get2DCoord(matchingNeighbours.get(key).get(0), n); xLastResort = coord2DLS[0]; yLastResort = coord2DLS[1]; chLastResort = currentChar; } if (value.size() > 1) { List nList = matchingNeighbours.get(key); int size = 1; for (i = 0; i < nList.size(); i++) { if (i == 0) { size += uf.getSize(nList.get(i)); } for (int j = 0; j < i; j++) { if (!uf.connected(nList.get(i), nList.get(j))) { size += uf.getSize(nList.get(i)); } } } if (maxSize < size) { maxSize = Math.max(maxSize, size); ch = key; x = coord2D[0]; y = coord2D[1]; } } if(value.size() > 2){ break; } } } if (maxSize != uf.getMaxSize()) { System.out.println((x + 1) + " " + (y + 1)); System.out.println(ch); } else { System.out.println((xLastResort + 1) + " " + (yLastResort + 1)); System.out.println(chLastResort); } } } // System.out.println("Ms: " + (System.currentTimeMillis() - start)); bi.close(); } private static void processNeighbor(Integer n, char[][] matrix, int[] coord2D, Map> matchingNeighbours, char currentChar) { char nChar = matrix[coord2D[0]][coord2D[1]]; if (currentChar != nChar) { addToMap(matchingNeighbours, nChar, get1DCoord(coord2D[0], coord2D[1], n)); } } private static void addToMap(Map> matchingNeighbours, char c, int coord) { List list; if (matchingNeighbours.containsKey(c)) { list = matchingNeighbours.get(c); list.add(coord); } else { list = new ArrayList(); list.add(coord); matchingNeighbours.put(c, list); } } private static int[] get2DCoord(int coord, int n) { return new int[] { coord / n, coord % n }; } private static int get1DCoord(int i, int j, int n) { return i * n + j; } public static class WeightedQuickUnionUF { private int[] parent; private int[] size; private int count; private int maxSize; public WeightedQuickUnionUF(int N) { count = N; parent = new int[N]; size = new int[N]; maxSize = 1; for (int i = 0; i < N; i++) { parent[i] = i; size[i] = 1; } } public int find(int p) { while (p != parent[p]) { p = parent[p]; } return p; } public int count() { return count; } public boolean connected(int p, int q) { return find(p) == find(q); } public int getMaxSize() { return maxSize; } public int getSize(int p) { return size[find(p)]; } public void union(int p, int q) { int rootP = find(p); int rootQ = find(q); if (rootP != rootQ) { if (size[rootP] < size[rootQ]) { parent[rootP] = rootQ; size[rootQ] += size[rootP]; maxSize = Math.max(maxSize, size[rootQ]); } else { parent[rootQ] = rootP; size[rootP] += size[rootQ]; maxSize = Math.max(maxSize, size[rootP]); } count--; } } } }