Problem:
Score : 800 points

Problem Statement

Mr. Takahashi has in his room an art object with H rows and W columns, made up of H \times W blocks.
Each block has a color represented by a lowercase English letter (a-z).
The color of the block at the i-th row and j-th column is c_{i,j}.

Mr. Takahashi would like to dismantle the object, finding it a bit kitschy for his tastes.
The dismantling is processed by repeating the following operation:

Choose one of the W columns and push down that column one row.
The block at the bottom of that column disappears.

Each time the operation is performed, a cost is incurred.
Since blocks of the same color have a property to draw each other together, the cost of the operation is the number of the pairs of blocks (p, q) such that:

The block p is in the selected column.

The two blocks p and q are horizontally adjacent (before pushing down the column).

The two blocks p and q have the same color.

Mr. Takahashi dismantles the object by repeating the operation H \times W times to get rid of all the blocks.
Compute the minimum total cost to dismantle the object.

Constraints

1 ≤ H ≤ 300

2 ≤ W ≤ 300

All characters c_{i,j} are lowercase English letters (a-z).

Partial Score

In test cases worth 300 points, W = 3.

Input

The input is given from Standard Input in the following format:

H W
c_{1,1}c_{1,2}..c_{1,W}
c_{2,1}c_{2,2}..c_{2,W}
:
c_{H,1}c_{H,2}..c_{H,W}

Output

Print the minimum total cost to dismantle the object.

Sample Input 1

2 3
rrr
brg

Sample Output 1

2

For example, the total cost of 2 can be achieved by performing the operation as follows and this is the minimum value.

Sample Input 2

6 3
xya
xya
ayz
ayz
xaz
xaz

Sample Output 2

0

The total cost of 0 can be achieved by first pushing down all blocks of the middle column, then all of the left column, and all of the right column.

Sample Input 3

4 2
ay
xa
xy
ay

Sample Output 3

0

The total cost of 0 can be achieved by the following operations:

pushing down the right column one row;

pushing down the left column one row;

pushing down all of the right column;

and pushing down all of the left column.

Sample Input 4

5 5
aaaaa
abbba
ababa
abbba
aaaaa

Sample Output 4

24

Sample Input 5

7 10
xxxxxxxxxx
ccccxxffff
cxxcxxfxxx
cxxxxxffff
cxxcxxfxxx
ccccxxfxxx
xxxxxxxxxx

Sample Output 5

130

Solution in Rust (1.15.1) (judge verdict: Time Limit Exceeded)

use std::io::{ self, Write };
use std::str::FromStr;
use std::cmp::{ min, max };
use std::collections::{ BinaryHeap, VecDeque, HashMap };

macro_rules! trace {
    ($var:expr) => ({
        let _ = writeln!(&mut std::io::stderr(), ">>> {} = {:?}", stringify!($var), $var);
    })
}
macro_rules! swap { ($a:expr, $b:expr) => ({ let t = $b; $b = $a; $a = t; }) }

fn main() {
    let mut sc = Scanner::new();
    let mut h: usize = sc.cin();
    let mut w: usize = sc.cin();
    trace!((h, w));

    let mut fs = vec![ vec![' '; h]; w];
    for i in 0..h {
        let line: String = sc.cin();
        let cs = line.chars().collect::<Vec<_>>();
        for j in 0..w {
            fs[j][h - i - 1] = cs[j];
        }
    }

    let mut memo = HashMap::new();
    memo.insert(vec![0usize; w], 0u64);

    let mut ps = vec![(0, vec![0usize; w])];
    while let Some((cost, p)) = ps.pop() {

        let mut finish = true;
        for i in 0..w {
            if p[i] != h { finish = false; break; }
        }
        if finish { continue; }

        let mut diff = vec![0; w - 1]; // diff of (i) and (i+1)
        for i in 0..(w-1) {
            let mut d = 0;
            for j in 0..h {
                if j + p[i] >= h || j + p[i+1] >= h { break; }
                if fs[i][j + p[i]] == fs[i+1][j + p[i + 1]] { d += 1; }
            }
            diff[i] = d;
        }

        for i in 0..w {
            if p[i] == h { continue; }
            let mut q = p.to_owned();
            q[i] += 1;
            let k = cost + (if i == 0 { 0 } else { diff[i-1] }) + (if i < w-1 { diff[i] } else { 0 });

            if let Some(&k2) = memo.get(&q) {
                if k2 > k {
                    memo.insert(q.to_owned(), k as u64);
                    ps.push((k, q.to_owned()));
                }
            } else {
                memo.insert(q.to_owned(), k as u64);
                ps.push((k, q.to_owned()));
            }
        }
    }

    {
        let p = vec![h; w];
        if let Some(c) = memo.get(&p) {
            println!("{}", c);
        }
    }

}

#[allow(dead_code)]
struct Scanner { stdin: io::Stdin, buffer: VecDeque<String>, }
#[allow(dead_code)]
impl Scanner {
    fn new() -> Scanner { Scanner { stdin: io::stdin(), buffer: VecDeque::new() } }
    fn reserve(&mut self) {
        while self.buffer.len() == 0 {
            let mut line = String::new();
            let _ = self.stdin.read_line(&mut line);
            for w in line.split_whitespace() {
                self.buffer.push_back(String::from(w));
            }
        }
    }
    fn cin<T: FromStr>(&mut self) -> T {
        self.reserve();
        match self.buffer.pop_front().unwrap().parse::<T>() {
            Ok(a) => a,
            Err(_) => panic!("parse err")
        }
    }
    fn get_char(&mut self) -> char {
        self.reserve();
        let head = self.buffer[0].chars().nth(0).unwrap();
        let tail = String::from( &self.buffer[0][1..] );
        if tail.len()>0 { self.buffer[0]=tail } else { self.buffer.pop_front(); }
        head
    }
}