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.*;
public class Main {
	static long MOD = 1000000007;
	public static void main(String[] args) {
		FastScanner sc = new FastScanner();
		int H = sc.nextInt();
		int W = sc.nextInt();
		if(W != 3) {
			System.out.println("0");
			return;
		}
		char[][] map = new char[H][W];
		for(int i = 0; i < H; i++) {
			map[i] = sc.next().toCharArray();
		}
		int score = 0;
		for(int i = 0; i < H * W; i++) {
			int[] count = new int[W];
			for(int j = 0; j < W; j++) {
				if(map[H-1][j] == '-') count[j] = (int)-MOD;
				else count[j]++;
			}
			for(int j = 0; j < W; j++) {
				for(int k = H - 2; k >= 0; k--) {
					if(j != 0) {
						if(map[H-1][j] == '-') ;
						else if(map[k][j - 1] == '-') ;
						else if(map[H-1][j] == map[k][j - 1]) count[j]++;
						
					}
					if(j != W-1) {
						if(map[H-1][j] == '-') ;
						else if(map[k][j + 1] == '-') ;
						else if(map[H-1][j] == map[k][j + 1]) count[j]++;
					}
				}
			}
			for(int j = 0; j < W; j++) {
				for(int k = 0; k < H-1; k++) {
					if(j != 0) {
						if(map[k][j] == '-') ;
						else if(map[k+1][j - 1] == '-') ;
						else if(map[k][j] == map[k+1][j - 1]) count[j]--;
						
					}
					if(j != W-1) {
						if(map[k][j] == '-') ;
						else if(map[k+1][j + 1] == '-') ;
						else if(map[k][j] == map[k+1][j + 1]) count[j]--;
					}
				}
			}
			for(int j = 0; j < W; j++) {
				for(int k = 0; k < H; k++) {
					if(j != 0) {
						if(map[k][j] == '-') ;
						else if(map[k][j - 1] == '-') ;
						else if(map[k][j] == map[k][j - 1]) count[j]--;
						
					}
					if(j != W-1) {
						if(map[k][j] == '-') ;
						else if(map[k][j] == '-') ;
						else if(map[k][j] == map[k][j + 1]) count[j]--;
					}
				}
			}
			int min = (int)-MOD;
			int id  = -1;
			
			for(int j = 0; j < W; j++) {
				if(min < count[j]) {
					min = count[j];
					id = j;
				}
			}
			for(int j = 0; j < H; j++) {
				if(id != 0) {
					if(map[j][id] == '-') ;
					else if(map[j][id-1] == '-') ;
					else if(map[j][id] == map[j][id - 1]) score++;
					
				}
				if(id != W-1) {
					if(map[j][id] == '-') ;
					else if(map[j][id+1] == '-') ;
					else if(map[j][id] == map[j][id + 1]) score++;
				}
			}
			
			for(int j = H-1; j >= 1; j--) {
				map[j][id] = map[j-1][id];
			}
			map[0][id] = '-';
			//System.out.println(min + " " + score);
			//for(int j = 0; j < H; j++) {
			//	System.out.println(String.valueOf(map[j]));
			//}
			
		}
		System.out.println(score);

	}
	
	
	
	
}
 
class FastScanner {
    private final InputStream in = System.in;
    private final byte[] buffer = new byte[1024];
    private int ptr = 0;
    private int buflen = 0;
    private boolean hasNextByte() {
        if (ptr < buflen) {
            return true;
        }else{
            ptr = 0;
            try {
                buflen = in.read(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (buflen <= 0) {
                return false;
            }
        }
        return true;
    }
    private int readByte() { if (hasNextByte()) return buffer[ptr++]; else return -1;}
    private boolean isPrintableChar(int c) { return 33 <= c && c <= 126;}
    private void skipUnprintable() { while(hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++;}
    public boolean hasNext() { skipUnprintable(); return hasNextByte();}
    public String next() {
        if (!hasNext()) throw new NoSuchElementException();
        StringBuilder sb = new StringBuilder();
        int b = readByte();
        while(isPrintableChar(b)) {
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }
    public long nextLong() {
        if (!hasNext()) throw new NoSuchElementException();
        long n = 0;
        boolean minus = false;
        int b = readByte();
        if (b == '-') {
            minus = true;
            b = readByte();
        }
        if (b < '0' || '9' < b) {
            throw new NumberFormatException();
        }
        while(true){
            if ('0' <= b && b <= '9') {
                n *= 10;
                n += b - '0';
            }else if(b == -1 || !isPrintableChar(b)){
                return minus ? -n : n;
            }else{
                throw new NumberFormatException();
            }
            b = readByte();
        }
    }
    public int nextInt() {
        if (!hasNext()) throw new NoSuchElementException();
        int n = 0;
        boolean minus = false;
        int b = readByte();
        if (b == '-') {
            minus = true;
            b = readByte();
        }
        if (b < '0' || '9' < b) {
            throw new NumberFormatException();
        }
        while(true){
            if ('0' <= b && b <= '9') {
                n *= 10;
                n += b - '0';
            }else if(b == -1 || !isPrintableChar(b)){
                return minus ? -n : n;
            }else{
                throw new NumberFormatException();
            }
            b = readByte();
        }
    }
}