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.42.0) (judge verdict: Accepted)

use std::io;
use std::str::FromStr;
use std::collections::HashSet;

fn input_tuple() -> (usize, usize) {
    let mut line: String = String::new();
    io::stdin().read_line(&mut line);
    let vec: Vec<usize> = line.split_whitespace().map(|s| s.parse().unwrap()).collect();
    (vec[0], vec[1])
}

fn input_char_vec() -> Vec<char> {
    let mut line: String = String::new();
    io::stdin().read_line(&mut line);
    line.trim().chars().collect()
}

fn idx(y: usize, x: usize, w: usize) -> usize {
    y * w + x
}

fn count(idx: usize, w: usize, grid: &Vec<char>, checker: &Vec<char>, visited: &mut HashSet<usize>) -> Vec<u64> {
    // println!("idx: {}", idx);
    visited.insert(idx);
    if grid[idx] != checker[idx] {
        return vec![0; 2];
    }
    let i: usize;
    if grid[idx] == '#' {
        i = 0;
    } else {
        i = 1;
    }
    let mut tmp = vec![0; 2];
    tmp[i] += 1;
    let h = grid.len() / w;
    if idx % w != w - 1 && !visited.contains(&(idx+1)) {
        let c = count(idx + 1, w, grid, checker, visited);
        tmp[0] += c[0];
        tmp[1] += c[1];
    }
    if idx % w != 0 && !visited.contains(&(idx-1)) {
        let c = count(idx - 1, w, grid, checker, visited);
        tmp[0] += c[0];
        tmp[1] += c[1];
    }
    if idx < (h - 1) * w && !visited.contains(&(idx+w)) {
        let c = count(idx + w, w, grid, checker, visited);
        tmp[0] += c[0];
        tmp[1] += c[1];
    }
    if idx > w - 1 && !visited.contains(&(idx-w)) {
        let c = count(idx - w, w, grid, checker, visited);
        tmp[0] += c[0];
        tmp[1] += c[1];
    }
    tmp
}

fn main() {
    let (h, w) = input_tuple();
    let mut grid: Vec<char> = Vec::new();
    for _ in 0..h {
        let mut row = input_char_vec();
        grid.append(&mut row);
    }
    let mut ans = 0 ;
    let mut checker: Vec<char> = Vec::new();
    for i in 0..h {
        for j in 0..w {
            if (i + j) % 2 == 0 {
                checker.push('.');
            } else {
                checker.push('#');
            }
        }
    }
    let mut visited: HashSet<usize> = HashSet::new();
    for i in 0..h {
        for j in 0..w {
            if !visited.contains(&idx(i, j, w)) {
                let c = count(idx(i, j, w), w, &grid, &checker, &mut visited);
                ans += c[0] * c[1];
            }
        }
    }

    let mut checker: Vec<char> = Vec::new();
    for i in 0..h {
        for j in 0..w {
            if (i + j) % 2 == 0 {
                checker.push('#');
            } else {
                checker.push('.');
            }
        }
    }
    let mut visited: HashSet<usize> = HashSet::new();
    for i in 0..h {
        for j in 0..w {
            if !visited.contains(&idx(i, j, w)) {

                let c = count(idx(i, j, w), w, &grid, &checker, &mut visited);
                ans += c[0] * c[1];
            }
        }
    }
    println!("{}", ans);
}