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: Wrong Answer)

using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using static System.Console;
using static System.Math;

namespace AtCoder
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program().Solve(new ConsoleInput(Console.In, ' '));
#if DEBUG
            ReadLine();
#endif
        }

        struct Point
        {
            public int x;
            public int y;

            public Point(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
        }

        void Solve(ConsoleInput cin)
        {
            int h = cin.ReadInt;
            int w = cin.ReadInt;

            bool[,] field = new bool[h, w];
            List<Point> blacks = new List<Point>();

            for (int i = 0; i < h; i++)
            {
                string str = cin.Read;

                for (int j = 0; j < w; j++)
                {
                    field[i, j] = str[j] == '#';
                    if (field[i, j])
                    {
                        blacks.Add(new Point(i, j));
                    }
                }
            }

            bool[,] gone = new bool[h, w];
            int result = 0;

            for (int i = 0; i < blacks.Count(); i++)
            {
                Point b = blacks[i];

                if (gone[b.x, b.y])
                {
                    continue;
                }

                int level = 1;
                int whiteCount = 0;

                Queue<Point> queue = new Queue<Point>();
                queue.Enqueue(b);
                gone[b.x, b.y] = true;

                while (queue.Count() != 0)
                {
                    Point now = queue.Dequeue();

                    for (int j = 0; j < 4; j++)
                    {
                        int nextX = 0;
                        int nextY = 0;

                        switch (j)
                        {
                            case 0:
                                nextX = now.x - 1;
                                nextY = now.y;
                                break;
                            case 1:
                                nextX = now.x;
                                nextY = now.y - 1;
                                break;
                            case 2:
                                nextX = now.x + 1;
                                nextY = now.y;
                                break;
                            case 3:
                                nextX = now.x;
                                nextY = now.y + 1;
                                break;
                            default:
                                nextX = nextY = 0;
                                break;
                        }


                        if (nextX >= 0
                            && nextX < h
                            && nextY >= 0
                            && nextY < w
                            && field[nextX, nextY] != field[now.x, now.y]
                            && !gone[nextX, nextY])
                        {
                            gone[nextX, nextY] = true;

                            if (field[nextX, nextY])
                            {
                                level++;
                            }
                            else
                            {
                                whiteCount++;
                            }

                            queue.Enqueue(new Point(nextX, nextY));
                        }
                    }
                }

                result += level * whiteCount;
            }

            Console.WriteLine(result);
        }

        class ConsoleInput
        {
            private readonly System.IO.TextReader _stream;
            private char _separator = ' ';
            private Queue<string> inputStream;

            public ConsoleInput(System.IO.TextReader stream, char separator = ' ')
            {
                this._separator = separator;
                this._stream = stream;
                inputStream = new Queue<string>();
            }

            public string Read
            {
                get
                {
                    if (inputStream.Count != 0) return inputStream.Dequeue();
                    string[] tmp = _stream.ReadLine().Split(_separator);
                    for (int i = 0; i < tmp.Length; ++i)
                        inputStream.Enqueue(tmp[i]);
                    return inputStream.Dequeue();
                }
            }

            public string ReadLine { get { return _stream.ReadLine(); } }
            public int ReadInt { get { return int.Parse(Read); } }
            public long ReadLong { get { return long.Parse(Read); } }
            public double ReadDouble { get { return double.Parse(Read); } }
            public string[] ReadStrArray(long N) { var ret = new string[N]; for (long i = 0; i < N; ++i) ret[i] = Read; return ret; }
            public int[] ReadIntArray(long N) { var ret = new int[N]; for (long i = 0; i < N; ++i) ret[i] = ReadInt; return ret; }
            public long[] ReadLongArray(long N) { var ret = new long[N]; for (long i = 0; i < N; ++i) ret[i] = ReadLong; return ret; }
        }
    }
}