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.42.0) (judge verdict: Accepted)

#![allow(unused_imports)]
#![allow(non_snake_case)]
use std::cmp::*;
use std::collections::*;
use std::io::Write;

#[allow(unused_macros)]
macro_rules! debug {
    ($($e:expr),*) => {
        #[cfg(debug_assertions)]
        $({
            let (e, mut err) = (stringify!($e), std::io::stderr());
            writeln!(err, "{} = {:?}", e, $e).unwrap()
        })*
    };
}

fn calc_cost(lwi: usize, lh: usize, rh: usize, h: usize, grid: &Vec<Vec<char>>) -> i64 {
    let mut ret = 0;
    if lh >= rh {
        for ri in 0..rh {
            let li = ri + (lh - rh);
            if grid[li][lwi] == grid[ri][lwi + 1] {
                ret += 1;
            }
        }
    } else {
        for li in 0..lh {
            let ri = li + (rh - lh);
            if grid[li][lwi] == grid[ri][lwi + 1] {
                ret += 1;
            }
        }
    }
    ret
}

fn solve(lwi: usize, h: usize, grid: &Vec<Vec<char>>) -> i64 {
    let mut l_largers = vec![vec![0; h + 1]; h + 1];
    for offset in 0..h {
        for rhi in 0..h - offset {
            if grid[rhi + offset][lwi] == grid[rhi][lwi + 1] {
                l_largers[offset][rhi + 1] = 1;
            }
            if rhi > 0 {
                l_largers[offset][rhi + 1] += l_largers[offset][rhi];
            }
        }
    }
    let mut r_largers = vec![vec![0; h + 1]; h + 1];
    for offset in 0..h {
        for lhi in 0..h - offset {
            if grid[lhi][lwi] == grid[lhi + offset][lwi + 1] {
                r_largers[offset][lhi + 1] = 1;
            }
            if lhi > 0 {
                r_largers[offset][lhi + 1] += r_largers[offset][lhi];
            }
        }
    }

    let mut dp = vec![vec![std::i64::MAX; h + 1]; h + 1];
    dp[h][h] = 0;
    for lhi in (0..h + 1).rev() {
        for rhi in (0..h + 1).rev() {
            let cost;
            if lhi >= rhi {
                cost = l_largers[lhi - rhi][rhi];
            } else {
                cost = r_largers[rhi - lhi][lhi];
            }
            if lhi > 0 {
                dp[lhi - 1][rhi] = min(dp[lhi - 1][rhi], dp[lhi][rhi] + cost);
            }
            if rhi > 0 {
                dp[lhi][rhi - 1] = min(dp[lhi][rhi - 1], dp[lhi][rhi] + cost);
            }
        }
    }
    dp[0][0]
}

fn main() {
    let v = read_vec::<usize>();
    let (h, w) = (v[0], v[1]);

    let mut grid = vec![vec![]; h];
    for i in 0..h {
        grid[i] = read::<String>().chars().collect::<Vec<_>>();
    }

    let mut ans = 0;
    for i in 0..w - 1 {
        ans += solve(i, h, &grid);
    }
    println!("{}", ans);
}

fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>()
        .split_whitespace()
        .map(|e| e.parse().ok().unwrap())
        .collect()
}