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 Kotlin (1.0.0) (judge verdict: Time Limit Exceeded)

import java.util.*

fun main(args: Array<String>) {
    val (h, w) = readLine()!!.split(" ").map { it.toInt() }
    val hs = (1..h).map { readLine()!!.split("").drop(1).take(w) }


    var starts = mutableListOf<Point>()
    for ((r, ws) in hs.withIndex()) {
        for ((c, s) in ws.withIndex()) {
            if (hs[r][c] == "#") {
                starts.add(Point(r, c, "#", null))
            }
        }
    }


    var points = mutableMapOf<Point, MutableList<Point>>()

    // キュー
    var queue = ArrayDeque<Point>()
    var moveY = arrayOf(1, 0, -1,  0)
    var moveX = arrayOf(0, 1,  0, -1)

    var visited = Array(h) { Array(w) {false} }

    for (b in starts) {
        queue.offerLast(b)
        visited[b.y][b.x] = true

        while (!queue.isEmpty()) {
            val p = queue.pollFirst()!!

            val children = mutableListOf<Point>()
            for (i in (0..3)) {
                val nextY = p.y + moveY[i]
                val nextX = p.x + moveX[i]
                if (nextY in 0 until h && nextX in 0 until w) {
                    val nextColor = hs[nextY][nextX]
                    if (p.color != nextColor) {
                        if (!visited[nextY][nextX]) {
                            val child = Point(nextY, nextX, nextColor, b)
                            children.add(child)
                        }
                    }
                }
            }

            for (child in children) {
                visited[child.y][child.x] = true
                queue.offerLast(child)

                if (child.color == "#") {
                    continue
                }

                if (points[child.parent!!] != null) {
                    var list = points[child.parent]!!
                    list.add(child)
                    points[child.parent] = list
                } else {
                    var list = mutableListOf(child)
                    points[child.parent] = list
                }
            }
        }

        visited = Array(h) { Array(w) {false} }
    }
    
    val ans = points.map { it.value.size }.sum()
    println(ans)
}

data class Point(val y: Int, val x: Int, val color: String, val parent: Point?)