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;
class AC {
    static void Main() {
        Sub s = new Sub();
        s.Main();
    }
}

struct NofBW {
    public int b, w;
    public NofBW(int x, int y) { b = x; w = y; }
}

public class Sub {
    public Sub() { }
    int H, W;
    Lib2D.JagArray2D<char> field;
    Lib2D.Array2D<int> joined;
    long ans = 0;

    public void Main() {
        string[] inp = Console.ReadLine().Split();
        H = int.Parse(inp[0]);
        W = int.Parse(inp[1]);
        field = new Lib2D.JagArray2D<char>(H);
        for (int y = 0; y < H; y++)field.values[y] = Console.ReadLine().ToCharArray();
        joined = new Lib2D.Array2D<int>(W + 2, H + 2, 0);
        for (int y = 0; y < H; y++) {
            for (int x = 0; x < W; x++) {
                joined[x + 1, y + 1] = Type(new Lib2D.Point(x, y));
            }
        }
        // joined.print();
        for (int y = 1; y <= H; y++) {
            for (int x = 1; x <= W; x++) {
                // Console.WriteLine("x = {0}, y = {1}", x, y);
                NofBW n = search(new Lib2D.Point(x, y), Type(new Lib2D.Point(x - 1, y - 1)));
                ans += (long)n.b * (long)n.w;
            }
        }
        Console.WriteLine(ans);
    }

    int Type(Lib2D.Point p) {
        int x = p.X, y = p.Y;
        return (field[p] == '#' && (x + y) % 2 == 0) || (field[p] == '.' && (x + y) % 2 == 1) ? 1 : 2;
    }
    int depth = 0;
    string Indent(int d) {
        string res = "";
        for (int i = 0; i < d; i++) {
            res += "    ";
        }
        return res;
    }
    NofBW search(Lib2D.Point p, int nowtype) {
        // Console.WriteLine(Indent(depth++) + "search(({0}, {1}), {2})", p.X, p.Y, nowtype);
        if (joined[p] == 0 || joined[p] != nowtype) {
            // Console.WriteLine(Indent(--depth) + "return");
            return new NofBW(0, 0);
        }
        joined[p] = 0;
        int bl = 0, wh = 0;
        foreach (var v in Lib2D.Vector.moveV()) {
            NofBW n = search(p + v, nowtype);
            bl += n.b;
            wh += n.w;
        }
        if (field[new Lib2D.Point(p.X - 1, p.Y - 1)] == '#') {
            // Console.WriteLine(Indent(--depth) + "return (black = {0}, white = {1})", bl + 1, wh);
            return new NofBW(bl + 1, wh);
        } else {
            // Console.WriteLine(Indent(--depth) + "return (black = {0}, white = {1})", bl, wh + 1);
            return new NofBW(bl, wh + 1);
        }
    }
}

namespace Lib2D {
    public struct JagArray2D<Type> {
        public Type[][] values;
        public JagArray2D(int h) { values = new Type[h][]; }
        public Type this [Point p] {
            get { return values[p.Y][p.X]; }
            set { values[p.Y][p.X] = value; }
        }
        public Type this [int y, int x] {
            get { return values[y][x]; }
            set { values[x][y] = value; }
        }
        public void print() {
            for (int y = 0; y < values.Length; y++) {
                for (int x = 0; x < values[y].Length; x++)Console.Write(values[y][x]);
                Console.WriteLine();
            }
        }
        public void print(int w1, int h1, int w2, int h2) {
            for (int h = h1; h <= h2; h++) {
                for (int w = w1; w <= w2; w++)Console.Write(values[h][w]);
                Console.WriteLine();
            }
        }
        public void print(Point p1, Point p2) { print(p1.X, p1.Y, p2.X, p2.Y); }
    }
    public struct Array2D<Type> {
        Type[, ] values;
        public Array2D(int w, int h) { values = new Type[w, h]; }
        public Array2D(int w, int h, Type v) {
            values = new Type[w, h];
            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)values[x, y] = v;
        }
        public Type this [Point p] {
            get { return values[p.X, p.Y]; }
            set { values[p.X, p.Y] = value; }
        }
        public Type this [int x, int y] {
            get { return values[x, y]; }
            set { values[x, y] = value; }
        }
        public void print() {
            for (int y = 0; y < values.GetLength(1); y++) {
                for (int x = 0; x < values.GetLength(0); x++)Console.Write(values[x, y]);
                Console.WriteLine();
            }
        }
        public void print(int w1, int h1, int w2, int h2) {
            for (int y = h1; y < h2; y++) {
                for (int x = w1; x < w2; x++)Console.Write(values[x, y]);
                Console.WriteLine();
            }
        }
        public void print(Point p1, Point p2) { print(p1.X, p1.Y, p2.X, p2.Y); }
    }
    public class Point {
        public int X, Y;

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

        public static Point O = new Point(0, 0);

        public static Vector operator -(Point p1, Point p2) { return new Vector(p1.X - p2.X, p1.Y - p2.Y); }
        public static bool operator ==(Point p1, Point p2) { return p1.X == p2.X && p1.Y == p2.Y; }
        public static bool operator !=(Point p1, Point p2) { return !(p1 == p2); }

        public static explicit operator Vector(Point p) { return new Vector(p.X, p.Y); }
    }
    public class Vector {
        public int X;
        public int Y;

        public Vector(int x, int y) { X = x; Y = y; }
        public static Vector Zero = new Vector(0, 0);

        public static Point operator +(Point p, Vector v) { return new Point(p.X + v.X, p.Y + v.Y); }
        public static Vector operator +(Vector v1, Vector v2) { return new Vector(v1.X + v2.X, v1.Y + v2.Y); }
        public static Vector operator -(Vector v1, Vector v2) { return new Vector(v1.X - v2.X, v1.Y - v2.Y); }
        public static Vector operator *(Vector v, int n) { return new Vector(v.X * n, v.Y * n); }
        public static Vector operator *(int n, Vector v) { return new Vector(v.X * n, v.Y * n); }
        public static Vector operator /(Vector v, int n) { return new Vector(v.X / n, v.Y / n); }

        public static bool operator ==(Vector v1, Vector v2) { return v1.X == v2.X && v1.Y == v2.Y; }
        public static bool operator !=(Vector v1, Vector v2) { return !(v1 == v2); }

        public static implicit operator Point(Vector v) { return new Point(v.X, v.Y); }

        public static Vector[] moveV() {
            Vector[] res = {
                new Vector(1, 0),
                new Vector(-1, 0),
                new Vector(0, 1),
                new Vector(0, -1),
            };
            return res;
        }
    }
}