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 Rust (1.15.1) (judge verdict: Time Limit Exceeded)

/*------------------------------------------------------------------*/
/*------------------------- begin template -------------------------*/
/*------------------------------------------------------------------*/

// ref: tanakh <https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8>
// diff: using Parser
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut parser = Parser::from_str($s);
        input_inner!{parser, $($r)*}
    };
    (parser = $parser:ident, $($r:tt)*) => {
        input_inner!{$parser, $($r)*}
    };
    (new_stdin_parser = $parser:ident, $($r:tt)*) => {
        let stdin = std::io::stdin();
        let reader = std::io::BufReader::new(stdin.lock());
        let mut $parser = Parser::new(reader);
        input_inner!{$parser, $($r)*}
    };
    ($($r:tt)*) => {
        input!{new_stdin_parser = parser, $($r)*}
    };
}

macro_rules! input_inner {
    ($parser:ident) => {};
    ($parser:ident, ) => {};
    ($parser:ident, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($parser, $t);
        input_inner!{$parser $($r)*}
    };
}

macro_rules! read_value {
    ($parser:ident, ( $($t:tt),* )) => {
        ( $(read_value!($parser, $t)),* )
    };
    ($parser:ident, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($parser, $t)).collect::<Vec<_>>()
    };
    ($parser:ident, chars) => {
        read_value!($parser, String).chars().collect::<Vec<char>>()
    };
    ($parser:ident, char_) => {
        read_value!($parser, String).chars().collect::<Vec<char>>()[0]
    };
    ($parser:ident, usize1) => {
        read_value!($parser, usize) - 1
    };
    ($parser:ident, i64_) => {
        $parser.fast_i64()
    };
    ($parser:ident, usize_) => {
        $parser.fast_i64() as usize
    };
    ($parser:ident, usize1_) => {
        ($parser.fast_i64() - 1) as usize
    };
    ($parser:ident, $t:ty) => {
        $parser.next::<$t>().expect("Parse error")
    };
}

use std::io;
use std::io::BufRead;
use std::str;

// ref: tatsuya6502 <https://qiita.com/tatsuya6502/items/cd448486f7ef7b5b8c7e>
// ref: wariuni <https://qiita.com/tatsuya6502/items/cd448486f7ef7b5b8c7e#comment-7040a5ae96305e884eb9>
// diff: using std::io::BufRead::fill_buf()
pub struct Parser<R> {
    pub reader: R,
    buf: Vec<u8>,
    pos: usize,
}

impl Parser<io::Empty> {
    pub fn from_str(s: &str) -> Parser<io::Empty> {
        Parser {
            reader: io::empty(),
            buf: s.as_bytes().to_vec(),
            pos: 0,
        }
    }
}

impl<R: BufRead> Parser<R> {
    pub fn new(reader: R) -> Parser<R> {
        Parser {
            reader: reader,
            buf: vec![],
            pos: 0,
        }
    }
    pub fn update_buf(&mut self) {
        self.buf.clear();
        self.pos = 0;
        loop {
            let (len, complete) = {
                let buf2 = self.reader.fill_buf().unwrap();
                self.buf.extend_from_slice(buf2);
                let len = buf2.len();
                (len, buf2[len - 1] <= 0x20)
            };
            self.reader.consume(len);
            if complete {
                break;
            }
        }
    }
    pub fn next<T: str::FromStr>(&mut self) -> Result<T, T::Err> {
        loop {
            let mut begin = self.pos;
            while begin < self.buf.len() && (self.buf[begin] <= 0x20) {
                begin += 1;
            }
            let mut end = begin;
            while end < self.buf.len() && (self.buf[end] > 0x20) {
                end += 1;
            }
            if begin != self.buf.len() {
                self.pos = end;
                return unsafe { str::from_utf8_unchecked(&self.buf[begin..end]) }.parse::<T>();
            } else {
                self.update_buf();
            }
        }
    }
    pub fn fast_i64(&mut self) -> i64 {
        loop {
            let mut begin = self.pos;
            while begin < self.buf.len() && (self.buf[begin] <= 0x20) {
                begin += 1;
            }
            if begin == self.buf.len() {
                self.update_buf();
                continue;
            }
            let mut res = 0;
            let (is_positive, mut end) = match self.buf[begin] {
                b'+' => (true, begin + 1),
                b'-' => (false, begin + 1),
                _ => (true, begin),
            };
            while end < self.buf.len() && (self.buf[end] > 0x20) {
                res = res * 10 + (self.buf[end] as i64 - '0' as i64);
                end += 1;
            }
            if begin != self.buf.len() {
                self.pos = end;
                return if is_positive { res } else { -res };
            } else {
                self.update_buf();
            }
        }
    }
}

#[allow(unused_imports)]
use std::cmp::*;
use std::ops::*;

pub fn gen_cum2<T: Add<Output = T> + Sub<Output = T> + Copy>(
    zero: T,
    xss: &Vec<Vec<T>>,
) -> Vec<Vec<T>> {
    let mut res = vec![vec![zero; xss[0].len() + 1]; xss.len() + 1];
    for (i, ref xs) in xss.iter().enumerate() {
        for (k, &x) in xs.iter().enumerate() {
            res[i + 1][k + 1] = res[i + 1][k] + res[i][k + 1] - res[i][k] + x;
        }
    }
    res
}

fn main() {
    input! {
        new_stdin_parser = parser,
    }
    let res = solve(&mut parser);
    print!("{}", res);
}

/*------------------------------------------------------------------*/
/*-------------------------- end template --------------------------*/
/*------------------------------------------------------------------*/

use std::fmt::Write;
fn solve<R: BufRead>(parser: &mut Parser<R>) -> String {
    let mut buf = String::new();
    input! {
        parser = parser,
        h: usize,
        w: usize,
        field: [chars; h],
    }
    let (indices, dp_size) = {
        //let w = 185;
        //let h = 185;
        let mut res = vec![vec![vec![]; w + 1]; h + 1];
        let mut i = 0;
        for y1 in 0..h + 1 {
            for x1 in 0..w + 1 {
                for y2 in y1..h + 1 {
                    res[y1][x1].push(i);
                    for x2 in x1..w + 1 {
                        i += 1;
                    }
                }
            }
        }
        (res, i)
    };
    let f = |x1: usize, y1: usize, x2: usize, y2: usize| {
        if h == 3 && w == 3 {
            //// eprintln!("y1={},x1={}.y2={},x2={}", y1,x1,y2,x2);
        }
        indices[y1][x1][y2 - y1] + x2 - x1
    };
    // eprintln!("dp_size = {}", dp_size);
    let mut dp = vec![120u8; dp_size];

    let mut xss = vec![vec![0; w]; h];
    for y in 0..h {
        for x in 0..w {
            if field[y][x] == '#' {
                xss[y][x] = 1;
            }
        }
    }
    let xssc = gen_cum2(0, &xss);
    for y1 in 0..h {
        for x1 in 0..w {
            for y2 in y1 + 1..h + 1 {
                for x2 in x1 + 1..w + 1 {
                    let h2 = y2 - y1;
                    let w2 = x2 - x1;
                    let t = xssc[y2][x2] + xssc[y1][x1] - xssc[y2][x1] - xssc[y1][x2];
                    if t == 0 || t == h2 * w2 {
                        // eprintln!("zero: ({}, {}) ({}, {})", x1, y1, x2, y2);
                        dp[f(x1, y1, x2, y2)] = 0;
                    }
                }
            }
        }
    }

    for h2 in 0..h + 1 {
        for w2 in 0..w + 1 {
            for y1 in 0..h + 1 {
                let y2 = y1 + h2;
                if y2 > h {
                    break;
                }
                for x1 in 0..w + 1 {
                    let x2 = x1 + w2;
                    if x2 > w {
                        break;
                    }
                    // eprintln!("update: f({},{},{},{})", x1,y1,x2,y2);
                    for y3 in y1..y2 {
                        dp[f(x1, y1, x2, y2)] = min(
                            dp[f(x1, y1, x2, y2)],
                            max(dp[f(x1, y1, x2, y3)], dp[f(x1, y3, x2, y2)]) + 1,
                        );
                    }
                    for x3 in x1..x2 {
                        dp[f(x1, y1, x2, y2)] = min(
                            dp[f(x1, y1, x2, y2)],
                            max(dp[f(x1, y1, x3, y2)], dp[f(x3, y1, x2, y2)]) + 1,
                        );
                    }
                }
            }
        }
    }
    let res = dp[f(0, 0, w, h)];
    if h == 3 && w == 3 {
        for y1 in 0..h {
            for x1 in 0..w {
                for y2 in y1 + 1..h + 1 {
                    for x2 in x1 + 1..w + 1 {
                        // eprintln!("dp[f({},{},{},{})] = {}", x1,y1,x2,y2,dp[f(x1,y1,x2,y2)]);
                    }
                }
            }
        }
    }
    writeln!(buf, "{}", res);
    buf
}