Problem:
Score : 1000 points

Problem Statement

Note the unusual memory limit.

For a rectangular grid where each square is painted white or black, we define its complexity as follows:

If all the squares are black or all the squares are white, the complexity is 0.

Otherwise, divide the grid into two subgrids by a line parallel to one of the sides of the grid, and let c_1 and c_2 be the complexities of the subgrids. There can be multiple ways to perform the division, and let m be the minimum value of \max(c_1, c_2) in those divisions. The complexity of the grid is m+1.

You are given a grid with H horizontal rows and W vertical columns where each square is painted white or black.
HW characters from A_{11} to A_{HW} represent the colors of the squares.
A_{ij} is # if the square at the i-th row from the top and the j-th column from the left is black, and A_{ij} is . if that square is white.

Find the complexity of the given grid.

Constraints

1 \leq H,W \leq 185

A_{ij} is # or ..

Input

Input is given from Standard Input in the following format:

H W
A_{11}A_{12}...A_{1W}
:
A_{H1}A_{H2}...A_{HW}

Output

Print the complexity of the given grid.

Sample Input 1

3 3
...
.##
.##

Sample Output 1

2

Let us divide the grid by the boundary line between the first and second columns.
The subgrid consisting of the first column has the complexity of 0, and the subgrid consisting of the second and third columns has the complexity of 1, so the whole grid has the complexity of at most 2.

Sample Input 2

6 7
.####.#
#....#.
#....#.
#....#.
.####.#
#....##

Sample Output 2

4

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using Debug = System.Diagnostics.Trace;
using SB = System.Text.StringBuilder;
using static System.Math;
using Number = System.Int32;
using System.Numerics;
namespace Program {
	using N = Int32;
	public class Solver {
		Random rnd = new Random(0);
		public void Solve() {
			var n = ri;
			var m = ri;
			var a = Enumerate(n, x => rs);
			//(i,j),(k,j) から complexity を保って伸ばせる右側の max
			var R = Enumerate(n, x => Enumerate(m, y => new int[n]));

			//(i,j),(i,l) から complexity を保って伸ばせる下側の max
			var D = Enumerate(n, x => Enumerate(m, y => new int[m]));
			for (N i = 0; i < n; i++)
				for (N j = 0; j < m; j++) {
					R[i][j][i] = j;
					while (R[i][j][i] + 1 < m && a[i][R[i][j][i] + 1] == a[i][j]) R[i][j][i]++;
					D[i][j][j] = i;
					while (D[i][j][j] + 1 < n && a[D[i][j][j] + 1][j] == a[i][j]) D[i][j][j]++;
				}
			for (int i = 0; i < n; i++)
				for (int j = 0; j < m; j++) {
					for (int k = i + 1; k < n; k++)
						if (a[i][j] == a[k][j]) R[i][j][k] = Min(R[k][j][k], R[i][j][k - 1]);
						else R[i][j][k] = (N)(j - 1);
					for (int l = j + 1; l < m; l++)
						if (a[i][j] == a[i][l]) D[i][j][l] = Min(D[i][l][l], D[i][j][l - 1]);
						else D[i][j][l] = (N)(i - 1);
				}

			var NR = Enumerate(n, x => Enumerate(m, y => new int[n]));
			var ND = Enumerate(n, x => Enumerate(m, y => new int[m]));
			for (int rank = 0; ; rank++) {
				if (R[0][0][n - 1] == m - 1) { Console.WriteLine(rank); return; }
				for (int i = 0; i < n; i++)
					for (int j = 0; j < m; j++) {
						for (int k = i; k < n; k++) {
							var nj = R[i][j][k];
							if (nj + 1 < m) nj = R[i][nj + 1][k];
							NR[i][j][k] = nj;
						}
						for (int l = j; l < m; l++) {
							var ni = D[i][j][l];
							if (ni + 1 < n) ni = D[ni + 1][j][l];
							ND[i][j][l] = ni;
						}
					}
				for (int i = 0; i < n; i++)
					for (int j = 0; j < m; j++) {
						for (int k = 0; k < n; k++) {
							var nj = NR[i][j][k];
							while (nj + 1 < m && ND[i][j][nj + 1] >= k) nj++;
							R[i][j][k] = nj;
						}
						for (int l = 0; l < m; l++) {
							var ni = ND[i][j][l];
							while (ni + 1 < n && NR[i][j][ni + 1] >= l) ni++;
							D[i][j][l] = ni;
						}
					}
			}


		}
		const long INF = 1L << 60;
		static int[] dx = { -1, 0, 1, 0 };
		static int[] dy = { 0, 1, 0, -1 };
		int ri { get { return sc.Integer(); } }
		long rl { get { return sc.Long(); } }
		double rd { get { return sc.Double(); } }
		string rs { get { return sc.Scan(); } }
		public IO.StreamScanner sc = new IO.StreamScanner(Console.OpenStandardInput());

		static T[] Enumerate<T>(int n, Func<int, T> f) {
			var a = new T[n];
			for (int i = 0; i < a.Length; ++i) a[i] = f(i);
			return a;
		}
		static public void Swap<T>(ref T a, ref T b) { var tmp = a; a = b; b = tmp; }
	}
}

#region main
static class Ex {
	static public string AsString(this IEnumerable<char> ie) { return new string(ie.ToArray()); }
	static public string AsJoinedString<T>(this IEnumerable<T> ie, string st = " ") {
		return string.Join(st, ie);
	}
	static public void Main() {
		Console.SetOut(new Program.IO.Printer(Console.OpenStandardOutput()) { AutoFlush = true });
		var solver = new Program.Solver();
		//* 
		var t = new System.Threading.Thread(solver.Solve, 50000000);
		//t.Start();
		//t.Join();
		//*/
		solver.Solve();
		Console.Out.Flush();
	}
}
#endregion
#region Ex
namespace Program.IO {
	using System.IO;
	using System.Text;
	using System.Globalization;

	public class Printer : StreamWriter {
		public override IFormatProvider FormatProvider { get { return CultureInfo.InvariantCulture; } }
		public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { }
	}

	public class StreamScanner {
		public StreamScanner(Stream stream) { str = stream; }

		public readonly Stream str;
		private readonly byte[] buf = new byte[1024];
		private int len, ptr;
		public bool isEof = false;
		public bool IsEndOfStream { get { return isEof; } }

		private byte read() {
			if (isEof) return 0;
			if (ptr >= len) {
				ptr = 0;
				if ((len = str.Read(buf, 0, 1024)) <= 0) {
					isEof = true;
					return 0;
				}
			}
			return buf[ptr++];
		}

		public char Char() {
			byte b = 0;
			do b = read(); while ((b < 33 || 126 < b) && !isEof);
			return (char)b;
		}
		public string Scan() {
			var sb = new StringBuilder();
			for (var b = Char(); b >= 33 && b <= 126; b = (char)read()) sb.Append(b);
			return sb.ToString();
		}
		public string ScanLine() {
			var sb = new StringBuilder();
			for (var b = Char(); b != '\n' && b != 0; b = (char)read()) if (b != '\r') sb.Append(b);
			return sb.ToString();
		}
		public long Long() { return isEof ? long.MinValue : long.Parse(Scan()); }
		public int Integer() { return isEof ? int.MinValue : int.Parse(Scan()); }
		public double Double() { return isEof ? double.NaN : double.Parse(Scan(), CultureInfo.InvariantCulture); }
	}
}

#endregion