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.*;
import java.util.*;

/**
 * Created by fcdkbear on 15.10.16.
 */
public class Main {

    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        new Task().solve(in, out);
        out.close();
    }


    static class Task {

        int[][] precompute;
        int[][][] dp;
        boolean[][][] wasInState;
        int h,w;

        int r(int shift0, int shift1, int shift2) {

            if ((shift1 == h) && (shift2 == h) && (shift0 == h)) {
                return 0;
            }
            if (wasInState[shift0][shift1][shift2]) {
                return dp[shift0][shift1][shift2];
            }
            wasInState[shift0][shift1][shift2] = true;
            int res = Integer.MAX_VALUE;
            if (shift0 != h) {
                res = Math.min(res, precompute[0][shift0 - shift1 + h] + r(shift0 + 1, shift1, shift2));
            }
            if (shift1 != h) {
                res = Math.min(res, precompute[0][shift0 - shift1 + h] + precompute[1][shift1 - shift2 + h] + r(shift0, shift1 + 1, shift2));
            }
            if (shift2 != h) {
                res = Math.min(res, precompute[1][shift1 - shift2 + h] + r(shift0, shift1, shift2 + 1));
            }
            dp[shift0][shift1][shift2] = res;
            return res;
        }

        public void solve(InputReader in, PrintWriter out) {

            h = in.nextInt();
            w = in.nextInt();
            String[] painting = new String[h];
            for (int i = 0; i < h; ++i) {
                painting[i] = in.next();
            }
            precompute = new int[w - 1][h + h + 1];
            for (int i = 0; i + 1 < w; ++i) {
                for (int difference = -h; difference <= h; ++difference) {
                    for (int j = 0; j < h; ++j) {
                        int neighbourJ = j + difference;
                        if ((neighbourJ >= 0) && (neighbourJ < h) && (painting[j].charAt(i) == painting[neighbourJ].charAt(i + 1))) {
                            precompute[i][difference + h]++;
                        }
                    }
                }
            }

            dp = new int[h + 1][h + 1][h + 1];
            wasInState = new boolean[h + 1][h + 1][h + 1];
            int res = r(0,0,0);
            out.println(res);
        }

    }

    static class InputReader {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

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

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

        public long nextLong() {
            return Long.parseLong(next());
        }

    }

}