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: Accepted)

use std::io;
use std::io::prelude::*;
use std::str::FromStr;


struct Reader{
    buf: Vec<String>
}
impl Reader {
    fn _readbuf(&mut self, input: &mut io::Lines<std::io::StdinLock>) {
        if self.buf.len() > 0 {
            return;
        }
        let line = &input.next().unwrap().unwrap();
        for ln in line.split(' ') {
            self.buf.push(ln.to_string())
        }
    }
    fn i32_next(&mut self, input: &mut io::Lines<std::io::StdinLock>) -> i32 {
        self._readbuf(input);
        let a = i32::from_str(&self.buf[0]).unwrap(); 
        self.buf.remove(0);
        return a;
    }
    fn string_next(&mut self, input: &mut io::Lines<std::io::StdinLock>) -> String {
        self._readbuf(input);
        let a = self.buf[0].clone();
        self.buf.remove(0);
        return a;
    }
}


struct DPTable {
   h: usize,
   w: usize,
   color: Vec<char>,
   csum: Vec<i32>,
   dpa: Vec<i32>,
   dpb: Vec<i32>,
}
impl DPTable {
    fn init(&mut self) {
        for _i in 0..(self.h * self.w as usize) {self.color.push(' ');}
        for _i in 0..((self.h + 1) * (self.w + 1) as usize) {self.csum.push(0);}
        for _i in 0..(self.h * self.w * self.h * 2 as usize) {self.dpa.push(0);}
        for _i in 0..(self.h * self.w * self.w * 2 as usize) {self.dpb.push(0);}
    }
    fn to_key(& self, nh: usize, nw: usize, nx: usize, _key: char) -> usize {
        let mut ret = nx;
        if _key == 'a' {
            ret += nh * self.w * self.h;
            ret += nw * self.h;
        } else if _key == 'b' {
            ret += nh * self.w * self.w;
            ret += nw * self.w;
        } else {
            assert!(false);
        }
        ret * 2
    }
    fn add_color(&mut self, nh: usize, nw: usize, c: char) {
        self.color[nh * self.w + nw] = c;
    }
    fn init_csum(&mut self) {
        for i in 0..self.h {
            for j in 0..self.w {
                let mut value = 0;
                if self.color[i * self.w + j] == '#' {
                    value = 1;
                }
                self.csum[(i + 1) * (self.w + 1) + j + 1] = value;
            }
        }
        for i in 0..self.h {
            for j in 0..self.w {
                let pos = (i + 1) * (self.w + 1) + (j + 1);
                let mut value = self.csum[pos];
                value += self.csum[pos - 1];
                value += self.csum[pos - self.w - 1];
                value -= self.csum[pos - self.w - 2];
                self.csum[pos] = value;
            }
        }
        for i in 0..self.h {
            for j in 0..self.w {
                for k in i..self.h {
                    let as_key = self.to_key(i, j, k, 'a');
                    if self.is_same(i, j, k, j) {
                        let mut x = j + 1;
                        while x < self.w {
                            if self.is_same(i, j, k, x as usize) == false {
                                 break;
                            }
                            x += 1;
                        }
                        self.dpa[as_key] = (x - 1) as i32;
                    } else {
                        self.dpa[as_key] = -9999;
                    }
                }
                for k in j..self.w {
                    let as_key = self.to_key(i, j, k, 'b');
                    if self.is_same(i, j, i, k) {
                        let mut x = i + 1;
                        while x < self.h {
                            if self.is_same(i, j, x as usize, k) == false {
                                 break;
                            }
                            x += 1;
                        }
                        self.dpb[as_key] = (x - 1) as i32;
                    } else {
                        self.dpb[as_key] = -9999;
                    }
                }
            }
        }
    }
    fn is_same(& self, nh1: usize, nw1: usize, nh2: usize, nw2: usize) -> bool {
        let mut value = self.csum[(nh2 + 1) * (self.w + 1) + (nw2 + 1)];
        value += self.csum[nh1 * (self.w + 1) + nw1];
        value -= self.csum[nh1 * (self.w + 1) + nw2 + 1];
        value -= self.csum[(nh2 + 1) * (self.w + 1) + nw1];
        if value == 0 {
            true
        } else if value == ((nh2 - nh1 + 1) * (nw2 - nw1 + 1)) as i32 {
            true
        } else {
            false
        }
    }
    fn reset(&mut self) {
        for i in 0..(self.h * self.w * self.h as usize) {
            let keyx = ((i as i32) * 2) as usize; 
            self.dpa[keyx + 1] = self.dpa[keyx];
            self.dpa[keyx] = 0;
        }
        for i in 0..(self.h * self.w * self.w as usize) {
            let keyx = ((i as i32) * 2) as usize; 
            self.dpb[keyx + 1] = self.dpb[keyx];
            self.dpb[keyx] = -9999;
        }
    }
    fn calc(&mut self, nh: usize, nw: usize, nx: usize, _key: char) {
        if _key == 'a' {
            let mut minv = nw as i32 - 1;
            let mut maxv = self.w as i32 - 1;
            let as_key = self.to_key(nh, nw, nx, 'a');
            if self.dpa[as_key + 1] >= 0 {
                minv = self.dpa[as_key + 1];
            }
            while minv < maxv {
                let half = ((minv + maxv + 1) / 2) as usize;
                let mut is_ok = false;
                // tate
                if self.dpa[as_key + 1] >= 0 {
                    let next = self.dpa[as_key + 1] + 1;
                    if next > half as i32 {
                        is_ok = true;
                    } else {
                        let as_key_t = self.to_key(nh, next as usize, nx, 'a');
                        if self.dpa[as_key_t + 1] >= half as i32 {
                            is_ok = true;
                        }
                    }
                }
                // yoko
                let as_key_h = self.to_key(nh, nw, half, 'b'); 
                let point = self.dpb[as_key_h + 1] + 1;
                if point >= 0 {
                    if point > nx as i32 {
                        is_ok = true;
                    } else {
                        let as_key_t = self.to_key(point as usize, nw, half, 'b'); 
                        let point2 = self.dpb[as_key_t + 1];
                        if point2 >= nx as i32 {  
                            is_ok = true;
                        }
                    }
                }
                if is_ok {
                    minv = half as i32;
                } else {
                    maxv = half as i32 - 1;
                }
            }
            if minv >= nw as i32 {
                self.dpa[as_key] = minv;
            } else {
                self.dpa[as_key] = -9999;
            }
        } else {
            let mut minv = nh as i32 - 1;
            let mut maxv = self.h as i32 - 1;
            let as_key = self.to_key(nh, nw, nx, 'b');
            if self.dpb[as_key + 1] >= 0 {
                minv = self.dpb[as_key + 1];
            }
            while minv < maxv {
                let half = ((minv + maxv + 1) / 2) as usize;
                let mut is_ok = false;
                // yoko
                if self.dpb[as_key + 1] >= 0 {
                    let next = self.dpb[as_key + 1] + 1;
                    if next > half as i32 {
                        is_ok = true;
                    } else {
                        let as_key_t = self.to_key(next as usize, nw, nx, 'b');
                        if self.dpb[as_key_t + 1] >= half as i32 {
                            is_ok = true;
                        }
                    }
                }
                // tate
                let as_key_h = self.to_key(nh, nw, half, 'a');
                let point = self.dpa[as_key_h + 1] + 1;
                if point >= 0 {
                    if point > nx as i32 {
                        is_ok = true;
                    } else {
                        let as_key_t = self.to_key(nh, point as usize, half, 'a');
                        let point2 = self.dpa[as_key_t + 1];
                        if point2 >= nx as i32 {  
                            is_ok = true;
                        }
                    }
                }
                if is_ok {
                    minv = half as i32;
                } else {
                    maxv = half as i32 - 1;
                }
            }
            if minv >= nh as i32 {
                self.dpb[as_key] = minv;
            } else {
                self.dpb[as_key] = -9999;
            }
        }
    }
}


fn main() {
    let stdin = io::stdin();
    let mut data = stdin.lock().lines();
    let mut rd = Reader{buf: Vec::new()};
    let h = rd.i32_next(&mut data) as usize;
    let w = rd.i32_next(&mut data) as usize;
    let mut table = DPTable {
        h: h, w: w, color: Vec::new(), csum: Vec::new(),
        dpa: Vec::new(), dpb: Vec::new(),
    };
    table.init();
    for i in 0..h {
        let s = rd.string_next(&mut data);
        for (j, c) in s.chars().enumerate() {
            table.add_color(i, j, c);
        }
    }
    table.reset();
    table.init_csum();
    let mut sol = 0;
    loop {
        let as_key = table.to_key(0, 0, h - 1, 'a');
        if table.dpa[as_key] == (w - 1) as i32 {
            break;
        }
        sol += 1;
        table.reset();
        for i in 0..h {
            for j in 0..w {
                for k in i..h {
                    table.calc(i, j, k, 'a');
                }
                for k in j..w {
                    table.calc(i, j, k, 'b');
                }
            }
        }
    }
    println!("{}", sol);
}