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

use std::cmp;

fn main() {
    let (r, w) = (std::io::stdin(), std::io::stdout());
    let mut sc = IO::new(r.lock(), w.lock());
    let h: usize = sc.read();
    let w: usize = sc.read();
    let board: Vec<Vec<char>> = (0..h).map(|_| sc.chars()).collect();

    let mut ans = 0;
    for j in 1..w {
        let a = (0..h).map(|i| board[h - 1 - i][j - 1]).collect();
        let b = (0..h).map(|i| board[h - 1 - i][j]).collect();
        let cost = calc(&a, &b);
        ans += cost;
    }
    println!("{}", ans);
}

fn calc(a: &Vec<char>, b: &Vec<char>) -> u64 {
    let h = a.len();
    let mut cost = vec![vec![0; h + 1]; h + 1];
    for broken_a in 0..(h + 1) {
        let mut c = 0;
        for i in 0..h {
            if i + broken_a >= h {
                break;
            }
            if a[i + broken_a] == b[i] {
                c += 1;
            }
        }
        cost[broken_a][0] = c;
        for i in 0..h {
            if broken_a + i >= h {
                break;
            }
            cost[broken_a + i + 1][i + 1] =
                cost[broken_a + i][i] - if a[broken_a + i] == b[i] { 1 } else { 0 };
        }
    }
    for broken_b in 0..(h + 1) {
        let mut c = 0;
        for i in 0..h {
            if i + broken_b >= h {
                break;
            }
            if a[i] == b[i + broken_b] {
                c += 1;
            }
        }
        cost[0][broken_b] = c;
        for i in 0..h {
            if broken_b + i >= h {
                break;
            }
            cost[i + 1][broken_b + i + 1] =
                cost[i][broken_b + i] - if a[i] == b[broken_b + i] { 1 } else { 0 };
        }
    }

    let mut dp = vec![vec![1 << 50; h + 1]; h + 1];
    dp[0][0] = 0;
    for i in 0..(h + 1) {
        for j in 0..(h + 1) {
            if i < h {
                dp[i + 1][j] = cmp::min(dp[i + 1][j], dp[i][j] + cost[i][j]);
            }
            if j < h {
                dp[i][j + 1] = cmp::min(dp[i][j + 1], dp[i][j] + cost[i][j]);
            }
        }
    }
    dp[h][h]
}

pub struct IO<R, W: std::io::Write>(R, std::io::BufWriter<W>);

impl<R: std::io::Read, W: std::io::Write> IO<R, W> {
    pub fn new(r: R, w: W) -> IO<R, W> {
        IO(r, std::io::BufWriter::new(w))
    }
    pub fn write<S: std::ops::Deref<Target = str>>(&mut self, s: S) {
        use std::io::Write;
        self.1.write(s.as_bytes()).unwrap();
    }
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .0
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n' || b == b'\r' || b == b'\t')
            .take_while(|&b| b != b' ' && b != b'\n' && b != b'\r' && b != b'\t')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}