#![warn(clippy::pedantic)]

use std::io::stdin;

use itertools::Itertools;

fn expand(galaxies: &[(usize, usize)], factor: usize) -> impl Iterator<Item = (usize, usize)> + '_ {
    fn find_holes<I>(it: &I) -> Vec<usize>
    where
        I: Iterator<Item = usize> + Clone,
    {
        (0..it.clone().max().unwrap())
            .filter(|n| !it.clone().contains(n))
            .collect()
    }

    let empty_rows = find_holes(&galaxies.iter().map(|&(row, _col)| row));
    let empty_cols = find_holes(&galaxies.iter().map(|&(_row, col)| col));

    galaxies.iter().map(move |&(x, y)| {
        let additional_rows = empty_rows.iter().filter(|&&row| row < x).count() * (factor - 1);
        let additional_cols = empty_cols.iter().filter(|&&col| col < y).count() * (factor - 1);

        (x + additional_rows, y + additional_cols)
    })
}

fn distances_sum<I: IntoIterator<Item = (usize, usize)>>(galaxies: I) -> usize {
    galaxies
        .into_iter()
        .combinations(2)
        .map(|pos| {
            let &[(x1, y1), (x2, y2)] = pos.as_slice() else {
                panic!()
            };
            x1.abs_diff(x2) + y1.abs_diff(y2)
        })
        .sum()
}

fn main() {
    let galaxies: Vec<_> = stdin()
        .lines()
        .map(Result::unwrap)
        .enumerate()
        .flat_map(|(row, l)| {
            l.into_bytes()
                .into_iter()
                .enumerate()
                .filter_map(move |(col, c)| (c == b'#').then_some((row, col)))
        })
        .collect();

    println!("{}", distances_sum(expand(&galaxies, 2)));
    println!("{}", distances_sum(expand(&galaxies, 1_000_000)));
}
