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 Rust (1.15.1) (judge verdict: Accepted)

// -----------------------------------------------
// Framework <https://github.com/vain0x/procon>
//
// See the bottom of file for solution.
// -----------------------------------------------

#![allow(unused_imports)]
#![allow(non_snake_case)]

use std::cell::RefCell;
use std::cmp::{max, min, Ordering};
use std::collections::*;
use std::fmt::{Debug, Formatter, Write as FmtWrite};
use std::io::{stderr, stdin, BufRead, Write};
use std::mem::{replace, swap};
use std::ops::*;
use std::rc::Rc;

#[allow(unused_macros)]
macro_rules! debug {
    ($($e:expr),*) => {
        #[cfg(debug_assertions)]
        $({
            let (e, mut err) = (stringify!($e), stderr());
            writeln!(err, "\x1B[33m{}\x1B[0m = {:?}", e, $e).unwrap()
        })*
    };
}

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) =>
        ((0..$n).map(|_| read!([$t])).collect::<Vec<_>>());
    ($($t:ty),+ ; $n:expr) =>
        ((0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>());
    ([$t:ty]) =>
        (rl().split_whitespace().map(|w| w.parse().unwrap()).collect::<Vec<$t>>());
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

#[allow(dead_code)]
fn rl() -> String {
    let mut buf = String::new();
    stdin().read_line(&mut buf).unwrap();
    buf.trim_right().to_owned()
}

// -----------------------------------------------
// Solution
// -----------------------------------------------

struct Dfs<'a> {
    H: usize,
    W: usize,
    done: Vec<Vec<bool>>,
    board: &'a Vec<Vec<char>>,
}

impl<'a> Dfs<'a> {
    fn run(mut self) {
        let mut s = 0_i64;

        for y in 0..self.H {
            for x in 0..self.W {
                if self.done[y][x] {
                    continue;
                }

                let mut whites = 0_i64;
                let mut blacks = 0;

                self.dfs(y, x, &mut whites, &mut blacks);

                debug!((y, x, whites, blacks));

                s += whites * blacks;
            }
        }

        println!("{}", s)
    }

    fn dfs(&mut self, y: usize, x: usize, whites: &mut i64, blacks: &mut i64) {
        if self.done[y][x] {
            return;
        }
        self.done[y][x] = true;

        if self.board[y][x] == '.' {
            *whites += 1;
        } else {
            *blacks += 1;
        }

        if y >= 1 {
            if self.board[y][x] != self.board[y - 1][x] {
                self.dfs(y - 1, x, whites, blacks);
            }
        }
        if x >= 1 {
            if self.board[y][x] != self.board[y][x - 1] {
                self.dfs(y, x - 1, whites, blacks);
            }
        }
        if y + 1 < self.H {
            if self.board[y][x] != self.board[y + 1][x] {
                self.dfs(y + 1, x, whites, blacks);
            }
        }
        if x + 1 < self.W {
            if self.board[y][x] != self.board[y][x + 1] {
                self.dfs(y, x + 1, whites, blacks);
            }
        }
    }
}

fn main() {
    let (H, W) = read!(usize, usize);
    let board = read![String; H]
        .into_iter()
        .map(|s| s.chars().collect::<Vec<_>>())
        .collect::<Vec<_>>();

    Dfs {
        H: H,
        W: W,
        board: &board,
        done: vec![vec![false; W]; H],
    }
    .run()
}