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++ (GCC 9.2.1) (judge verdict: Time Limit Exceeded)

//ヘッダー
#include<bits/stdc++.h>
using namespace std;

//型定義
typedef long long ll;

//定数
const int INF=1e+9;
const int MOD=1e+9+7;

//REPマクロ
#define REP(i,n) for(ll i=0;i<(ll)(n);i++)
#define REPD(i,n) for(ll i=n-1;i>=0;i--)
#define REP2(i,a,b) for(ll i=a;i<(ll)(b);i++)
#define REPD2(i,a,b) for(ll i=a;i>(ll)(b);i--)

// 多次元 vector 生成
template<class T>
vector<T> make_vec(size_t a){
    return vector<T>(a);
}
template<class T, class... Ts>
auto make_vec(size_t a, Ts... ts){
  return vector<decltype(make_vec<T>(ts...))>(a, make_vec<T>(ts...));
}

//vectorの扱い
#define ALL(x) (x).begin(),(x).end() //sortなどの引数省略
#define SIZE(x) ((ll)(x).size()) //size
#define MAX(x) *max_element(ALL(x)) //最大値
#define MIN(x) *min_element(ALL(x)) //最小値


const vector<pair<int,int>> np={{-1,0},{1,0},{0,-1},{0,1}};

int main(){
    int H,W;
    cin>>H>>W;
    vector<vector<char>> S(510,vector<char>(510,'x'));    
    REP(i,H){
        string s;
        cin>>s;
        REP(j,s.size()){
            S[i+1][j+1]=s[j];
        }
    }
    ll ans=0;
    REP2(i,1,H+1){
        REP2(j,1,W+1){
            if(S[i][j]=='x') continue;
            // BFS のためのデータ構造
            vector<vector<int>> dist(510,vector<int>(510,-1)); // 全頂点を「未訪問」に初期化
            queue<pair<int,int>> que;
            
            // 初期条件 (頂点 0 を初期ノードとする)
            dist[i][j] = 0;
            que.push(make_pair(i,j)); // 0 を橙色頂点にする
            ll cnt1=0;
            ll cnt2=0;
            // BFS 開始 (キューが空になるまで探索を行う)
            while (!que.empty()) {
                pair<int,int> t = que.front(); // キューから先頭頂点を取り出す
                que.pop();
                int x=t.first;
                int y=t.second;
                
                if(S[x][y]=='#') cnt1++;
                if(S[x][y]=='.') cnt2++;
                char bv=S[x][y];
                S[x][y]='x';
                
                // v から辿れる頂点をすべて調べる
                for (auto n : np) {
                    int nx=x+n.first;
                    int ny=y+n.second;
                    if (S[nx][ny]=='x') continue;
                    if (S[nx][ny]==bv) continue;
                    if (dist[nx][ny]!=-1) continue;
                    // 新たな白色頂点 nv について距離情報を更新してキューに追加する
                    dist[nx][ny] = dist[x][y] + 1;
                    que.push(make_pair(nx,ny));
                }
            }
            ans+=cnt1*cnt2;
        }
    }
    cout<<ans<<endl;
    

}