Problem:
Score : 300 points

Problem Statement

There is a grid with H rows and W columns, where each square is painted black or white.

You are given H strings S_1, S_2, ..., S_H, each of length W.
If the square at the i-th row from the top and the j-th column from the left is painted black, the j-th character in the string S_i is #; if that square is painted white, the j-th character in the string S_i is ..

Find the number of pairs of a black square c_1 and a white square c_2 that satisfy the following condition:

There is a path from the square c_1 to the square c_2 where we repeatedly move to a vertically or horizontally adjacent square through an alternating sequence of black and white squares: black, white, black, white...

Constraints

1 \leq H, W \leq 400

|S_i| = W (1 \leq i \leq H)

For each i (1 \leq i \leq H), the string S_i consists of characters # and ..

Input

Input is given from Standard Input in the following format:

H W
S_1
S_2
:
S_H

Output

Print the answer.

Sample Input 1

3 3
.#.
..#
#..

Sample Output 1

10

Some of the pairs satisfying the condition are ((1, 2), (3, 3)) and ((3, 1), (3, 2)), where (i, j) denotes the square at the i-th row from the top and the j-th column from the left.

Sample Input 2

2 4
....
....

Sample Output 2

0

Sample Input 3

4 3
###
###
...
###

Sample Output 3

6

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;

class Program {
    static Scanner cin = new Scanner();

    struct p {
        public int x, y;
        public p(int X, int Y) {
            x = X;
            y = Y;
        }
    }

    static void Main(string[] args) {
        int H = cin.Int();
        int W = cin.Int();
        var S = new string[H+2];

        for (int i = 1; i <= H; i++) {
            S[i] = "." + Console.ReadLine() + ".";
        }

        int[] dx = { 1, 0, -1, 0 };
        int[] dy = { 0, 1, 0, -1 };

        long ans = 0;
        var isSearched = new bool[H + 2, W + 2];

        for (int i = 0; i < W+2; i++) {
            isSearched[0, i] = true;
            isSearched[H + 1, i] = true;
        }
        for (int i = 0; i < H+2; i++) {
            isSearched[i, 0] = true;
            isSearched[i, W + 1] = true;
        }

        for (int i = 1; i <= H; i++) {
            for (int j = 1; j <= W; j++) {
                if (!isSearched[i, j]) {
                    int black = 0, white = 0;
                    Queue<p> que = new Queue<p>();
                    que.Enqueue(new p(j, i));
                    isSearched[i, j] = true;
                    while (que.Count > 0) {
                        p point = que.Dequeue();
                        if (S[point.y][point.x] == '#') black++;
                        else if(S[point.y][point.x] == '.') white++;
                        for (int k = 0; k < 4; k++) {
                            int ni = point.y + dy[k];
                            int nj = point.x + dx[k];
                            if (1 <= ni && ni <= H && 1 <= nj && nj <= W && !isSearched[ni, nj] && S[point.y][point.x] != S[ni][nj]) {
                                    que.Enqueue(new p(nj, ni));
                                    isSearched[ni, nj] = true;
                            }
                        }
                    }
                    ans += (long)black * (long)white;
                }
            }
        }
        Console.WriteLine(ans);
        Console.ReadLine();
    }
}

class Scanner //標準入力
{
    string[] s;
    int i;

    char[] cs = new char[] { ' ' };

    public Scanner()
    {
        s = new string[0];
        i = 0;
    }

    public string next()
    {
        if (i < s.Length) return s[i++];
        string st = Console.ReadLine();
        while (st == "") st = Console.ReadLine();
        s = st.Split(cs, StringSplitOptions.RemoveEmptyEntries);
        if (s.Length == 0) return next();
        i = 0;
        return s[i++];
    }

    public int Int()
    {
        return int.Parse(next());
    }
    public int[] ArrayInt(int N, int add = 0)
    {
        int[] Array = new int[N];
        for (int i = 0; i < N; i++)
        {
            Array[i] = Int() + add;
        }
        return Array;
    }

    public long Long()
    {
        return long.Parse(next());
    }

    public long[] ArrayLong(int N, long add = 0)
    {
        long[] Array = new long[N];
        for (int i = 0; i < N; i++)
        {
            Array[i] = Long() + add;
        }
        return Array;
    }
}