Problem:
Score : 600 points

Problem Statement

There is a board with N rows and M columns.
The information of this board is represented by N strings S_1,S_2,\ldots,S_N.
Specifically, the state of the square at the i-th row from the top and the j-th column from the left is represented as follows:

S_{i,j}=. : the square is empty.

S_{i,j}=# : an obstacle is placed on the square.

S_{i,j}=o : a piece is placed on the square.

Yosupo repeats the following operation:

Choose a piece and move it to its right adjecent square or its down adjacent square.
Moving a piece to squares with another piece or an obstacle is prohibited.
Moving a piece out of the board is also prohibited.

Yosupo wants to perform the operation as many times as possible.
Find the maximum possible number of operations.

Constraints

1 \leq N \leq 50

1 \leq M \leq 50

S_i is a string of length M consisting of ., # and o.

1 \leq ( the number of pieces )\leq 100.
In other words, the number of pairs (i, j) that satisfy S_{i,j}=o is between 1 and 100, both inclusive.

Input

Input is given from Standard Input in the following format:

N M
S_1
S_2
\vdots
S_N

Output

Print the maximum possible number of operations in a line.

Sample Input 1

3 3
o..
...
o.#

Sample Output 1

4

Yosupo can perform operations 4 times as follows:

o.. .o. ..o ... ...
... -> ... -> ... -> ..o -> ..o
o.# o.# o.# o.# .o#

Sample Input 2

9 10
.#....o#..
.#..#..##o
.....#o.##
.###.#o..o
#.#...##.#
..#..#.###
#o.....#..
....###..o
o.......o#

Sample Output 2

24

Solution in Rust (1.42.0) (judge verdict: Accepted)

macro_rules! read_line_to_tuple {
    ( $( $t:ty ),* ) => {{
        let mut input = String::new();
        std::io::stdin().read_line(&mut input).unwrap();
        let mut iter = input.split_whitespace();
        ( $( iter.next().unwrap().parse::<$t>().unwrap() ),* )
    }};
}

use std::collections::BinaryHeap;
use std::cmp::Reverse;

#[derive(Clone, Copy)]
struct Edge {
    to: usize, rev: usize, cap: i64, cost: i64,
}

impl Edge {
    fn new(to: usize, rev: usize, cap: i64, cost: i64) -> Edge {
        Edge { to, rev, cap, cost, }
    }
}

struct PrimalDual {
    n: usize,
    g: Vec<Vec<Edge>>,
}

impl PrimalDual {
    fn new(n: usize) -> PrimalDual {
        PrimalDual {
            n,
            g: vec![vec![]; n],
        }
    }

    fn add_edge(&mut self, from: usize, to: usize, cap: i64, cost: i64) {
        let rev = self.g[to].len();
        self.g[from].push(Edge::new(to, rev, cap, cost));
        let rev = self.g[from].len() - 1;
        self.g[to].push(Edge::new(from, rev, 0, -cost));
    }

    fn min_cost_flow(&mut self, s: usize, t: usize, flow_limit: i64) -> i64 {
        let mut res = 0;
        let mut heap = BinaryHeap::new();
        let mut min_cost = vec![0; self.n];
        let mut prev_v = vec![!0; self.n];
        let mut prev_e = vec![!0; self.n];

        let mut flow = 0;
        while flow < flow_limit {
            min_cost.iter_mut().for_each(|c| *c = std::i64::MAX);
            prev_v.iter_mut().for_each(|v| *v = !0);
            prev_e.iter_mut().for_each(|e| *e = !0);
            heap.push((Reverse(0), s));
            min_cost[s] = 0;
            while let Some((Reverse(cost), v)) = heap.pop() {
                for (i, e) in self.g[v].iter().enumerate() {
                    let next_cost = cost + e.cost;
                    if e.cap > 0 && next_cost < min_cost[e.to] {
                        min_cost[e.to] = next_cost;
                        prev_v[e.to] = v;
                        prev_e[e.to] = i;
                        heap.push((Reverse(next_cost), e.to));
                    }
                }
            }

            let mut v = t;
            while v != s {
                self.g[prev_v[v]][prev_e[v]].cap -= 1;
                let rev = self.g[prev_v[v]][prev_e[v]].rev;
                self.g[v][rev].cap += 1;
                res += self.g[prev_v[v]][prev_e[v]].cost;
                v = prev_v[v];
            }

            flow += 1;
        }

        res
    }
}

use std::collections::VecDeque;
use std::cmp::max;

fn main() {
    let (n, m) = read_line_to_tuple!(usize, usize);
    let grid: Vec<Vec<char>> = {
        (0..n)
            .map(|_| read_line_to_tuple!(String).chars().collect())
            .collect()
    };

    let mut pd = PrimalDual::new(n * m + 2);
    let (s, t) = (n * m, n * m + 1);
    let mut k = 0;

    let mut que = VecDeque::with_capacity(max(n, m));
    let mut check = vec![false; n * m];
    for i in 0..n {
        for j in 0..m {
            if grid[i][j] != '#' {
                pd.add_edge(i * m + j, t, 1, 0);
            }
            if grid[i][j] != 'o' { continue; }
            pd.add_edge(s, i * m + j, 1, 0);
            k += 1;
            que.clear();
            check.iter_mut().for_each(|c| *c = false);
            que.push_back(i * m + j);
            check[i * m + j] = true;
            while let Some(v) = que.pop_front() {
                let (x, y) = (v / m, v % m);
                pd.add_edge(i * m + j, x * m + y, 1, -1 * ((x - i) + (y - j)) as i64);
                if x + 1 < n && grid[x + 1][y] != '#' && !check[(x + 1) * m + y] {
                    que.push_back((x + 1) * m + y);
                    check[(x + 1) * m + y] = true;
                }
                if y + 1 < m && grid[x][y + 1] != '#' && !check[x * m + (y + 1)] {
                    que.push_back(x * m + (y + 1));
                    check[x * m + (y + 1)] = true;
                }
            }
        }
    }

    println!("{}", -pd.min_cost_flow(s, t, k));
}