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: Time Limit Exceeded)

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

public struct Point
{
    public int X;
    public int Y;

    public Point(Point p)
    {
        X = p.X;
        Y = p.Y;
    }

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

    public static bool operator ==(Point a, Point b)
    {
        return (a.X == b.X && a.Y == b.Y);
    }

    public static bool operator !=(Point a, Point b)
    {
        return !(a == b);
    }

    //objと自分自身が等価のときはtrueを返す
    public override bool Equals(object obj)
    {
        if (!(obj is Point))
        {
            return false;
        }

        Point p = (Point)obj;
        return (X == p.X && Y == p.Y);
    }

    //Equalsがtrueを返すときに同じ値を返す
    public override int GetHashCode()
    {
        return (X << 16) ^ Y;
    }

    public Point Clone()
    {
        return new Point(X, Y);
    }

    public void Reverse()
    {
        X = -X;
        Y = -Y;
    }

    public static Point operator +(Point a, Point b)
    {
        return new Point(a.X + b.X, a.Y + b.Y);
    }

    public static Point operator -(Point a, Point b)
    {
        return new Point(a.X - b.X, a.Y - b.Y);
    }

    public static Point operator *(Point a, int i)
    {
        return new Point(a.X * i, a.Y * i);
    }

    public static Point operator /(Point a, int i)
    {
        return new Point(a.X / i, a.Y / i);
    }
    public static Point operator +(Point a)
    {
        return new Point(+a.X, +a.Y);
    }

    public static Point operator -(Point a)
    {
        return new Point(-a.X, -a.Y);
    }

    public override string ToString()
    {
        return string.Format("({0},{1})", X, Y);
    }

    IEnumerable<Point> GetNeighbor()
    {
        yield return new Point(X + 1, Y + 0);
        yield return new Point(X + 0, Y + 1);
        yield return new Point(X - 1, Y + 0);
        yield return new Point(X + 0, Y - 1);
    }

    public IEnumerable<Point> GetNeighbor(Point max)
    {
        return GetNeighbor().Where(p => p.InRange(max));
    }

    public bool InRange(Point max)
    {
        return 0 <= X && X < max.X && 0 <= Y && Y < max.Y;
    }
}

public class Solution
{
    static Point Max;
    static string[] Grid;

    static int ToIndex(Point p)
    {
        return p.Y * Max.X + p.X;
    }

    static int Count(Point start)
    {
        if (Grid[start.Y][start.X] != '#')
        {
            return 0;
        }

        var queue = new Queue<Point>();
        var visit = new HashSet<Point>();
        queue.Enqueue(start);
        visit.Add(start);
        int count = 0;

        while (queue.Count > 0)
        {
            var p = queue.Dequeue();
            var color = Grid[p.Y][p.X];

            foreach (var nei in p.GetNeighbor(Max))
            {
                if (visit.Contains(nei))
                {
                    continue;
                }
                var neiColor = Grid[nei.Y][nei.X];
                if (color == neiColor)
                {
                    continue;
                }

                if (neiColor == '.')
                {
                    count++;
                }
                queue.Enqueue(nei);
                visit.Add(nei);
            }
        }
        return count;
    }

    public static void Main()
    {
        var vals = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();
        Max = new Point(vals[1], vals[0]);
        Grid = new string[Max.Y];
        for (int i = 0; i < Max.Y; i++)
        {
            Grid[i] = Console.ReadLine();
        }

        int count = 0;
        for (int y = 0; y < Max.Y; y++)
        {
            for (int x = 0; x < Max.X; x++)
            {
                count += Count(new Point(x, y));
            }
        }

        Console.WriteLine(count);
    }
}