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 Java8 (OpenJDK 1.8.0) (judge verdict: Wrong Answer)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		FastScanner in = new FastScanner(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		ProblemD solver = new ProblemD();
		solver.solve(1, in, out);
		out.close();
	}

	static class ProblemD {
		public void solve(int testNumber, FastScanner in, PrintWriter out) {
			int height = in.nextInt();
			int width = in.nextInt();
			char[][] s = new char[height][];
			for (int r = 0; r < height; r++) {
				s[r] = in.next().toCharArray();
			}
			final int infinity = 1000000000;
			int n = height;
			int[][] c1 = new int[n + 1][n + 1];
			int[][] c2 = new int[n + 1][n + 1];
			for (int s1 = 0; s1 <= n; s1++) {
				for (int s2 = 0; s2 <= n; s2++) {
					for (int r = 0; r < height; r++) {
						if (r >= s1 && r >= s2 && s[r - s1][0] == s[r - s2][1]) {
							++c1[s1][s2];
						}
						if (width == 3 && r >= s1 && r >= s2 && s[r - s1][1] == s[r - s2][2]) {
							++c2[s1][s2];
						}
					}
				}
			}
			int[][][] d = new int[n + 1][n + 1][n + 1];
			for (int s1 = n; s1 >= 0; s1--) {
				for (int s2 = n; s2 >= 0; s2--) {
					for (int s3 = n; s3 >= 0; s3--) {
						if (s1 == n && s2 == n && s3 == n) {
							d[s1][s2][s3] = 0;
						} else {
							d[s1][s2][s3] = infinity;
						}
						if (s1 < n) {
							d[s1][s2][s3] = Math.min(d[s1][s2][s3], d[s1 + 1][s2][s3] + c1[s1][s2]);
						}
						if (s2 < n) {
							d[s1][s2][s3] = Math.min(d[s1][s2][s3], d[s1][s2 + 1][s3] + c1[s1][s2] + c2[s2][s3]);
						}
						if (s3 < n) {
							d[s1][s2][s3] = Math.min(d[s1][s2][s3], d[s1][s2][s3 + 1] + c2[s2][s3]);
						}
					}
				}
			}
			if (width == 2) {
				out.println(d[0][0][n]);
			} else {
				out.println(d[0][0][0]);
			}
		}

	}

	static class FastScanner {
		private BufferedReader in;
		private StringTokenizer st;

		public FastScanner(InputStream stream) {
			in = new BufferedReader(new InputStreamReader(stream));
		}

		public String next() {
			while (st == null || !st.hasMoreTokens()) {
				try {
					st = new StringTokenizer(in.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return st.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

	}
}