Problem:
Score : 700 points

Problem Statement

There are some coins in the xy-plane.
The positions of the coins are represented by a grid of characters with H rows and W columns.
If the character at the i-th row and j-th column, s_{ij}, is #, there is one coin at point (i,j); if that character is ., there is no coin at point (i,j). There are no other coins in the xy-plane.

There is no coin at point (x,y) where 1\leq i\leq H,1\leq j\leq W does not hold.
There is also no coin at point (x,y) where x or y (or both) is not an integer.
Additionally, two or more coins never exist at the same point.

Find the number of triples of different coins that satisfy the following condition:

Choosing any two of the three coins would result in the same Manhattan distance between the points where they exist.

Here, the Manhattan distance between points (x,y) and (x',y') is |x-x'|+|y-y'|.
Two triples are considered the same if the only difference between them is the order of the coins.

Constraints

1 \leq H,W \leq 300

s_{ij} is # or ..

Input

Input is given from Standard Input in the following format:

H W
s_{11}...s_{1W}
:
s_{H1}...s_{HW}

Output

Print the number of triples that satisfy the condition.

Sample Input 1

5 4
#.##
.##.
#...
..##
...#

Sample Output 1

3

((1,1),(1,3),(2,2)),((1,1),(2,2),(3,1)) and ((1,3),(3,1),(4,4)) satisfy the condition.

Sample Input 2

13 27
......#.........#.......#..
#############...#.....###..
..............#####...##...
...#######......#...#######
...#.....#.....###...#...#.
...#######....#.#.#.#.###.#
..............#.#.#...#.#..
#############.#.#.#...###..
#...........#...#...#######
#..#######..#...#...#.....#
#..#.....#..#...#...#.###.#
#..#######..#...#...#.#.#.#
#..........##...#...#.#####

Sample Output 2

870

Solution in Rust (1.15.1) (judge verdict: Time Limit Exceeded)

fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>()
        .split_whitespace()
        .map(|e| e.parse().ok().unwrap())
        .collect()
}

fn manhattan_dist(x1: i32, y1: i32, x2: i32, y2: i32) -> usize {
    ((x1 - x2).abs() + (y1 - y2).abs()) as usize
}

fn main() {
    let v: Vec<usize> = read_vec();
    let (h, w) = (v[0], v[1]);
    let mut grid: Vec<Vec<bool>> = Vec::new();
    for _ in 0..h {
        let s: String = read();
        let mut line: Vec<bool> = Vec::new();
        for ch in s.chars() {
            if ch == '#' {
                line.push(true);
            } else {
                line.push(false);
            }
        }
        grid.push(line);
    }

    let mut rt_to_lb_group = Vec::new();
    for i in 0..h + w - 1 {
        let mut x = 0;
        let mut y = i as i32;
        let mut line = Vec::new();
        while y >= 0 && x < w as i32 {
            if x >= 0 && x < w as i32 && y >= 0 && y < h as i32 && grid[y as usize][x as usize] {
                // if x >= 0 && x < w as i32 && y >= 0 && y < h as i32 {
                line.push((x, y));
            }
            x += 1;
            y -= 1;
        }
        rt_to_lb_group.push(line);
    }

    // println!("{:?}", rt_to_lb_group);

    let mut rb_to_lt_group = Vec::new();
    for i in 0..h + w - 1 {
        let mut x = 0;
        let mut y = h as i32 - i as i32 - 1;
        let mut line = Vec::new();
        while x >= 0 && y < h as i32 {
            if x >= 0 && x < w as i32 && y >= 0 && y < h as i32 && grid[y as usize][x as usize] {
                // if x >= 0 && x < w as i32 && y >= 0 && y < h as i32 {
                line.push((x, y));
            }
            x += 1;
            y += 1;
        }
        rb_to_lt_group.push(line);
    }

    // println!("{:?}", rb_to_lt_group);

    let mut ans_set = std::collections::HashSet::new();

    for (line_index, line) in rt_to_lb_group.iter().by_ref().enumerate() {
        if line.len() < 2 {
            continue;
        }
        for i in 0..line.len() - 1 {
            for j in i + 1..line.len() {
                let dist = manhattan_dist(line[i].0, line[i].1, line[j].0, line[j].1);
                if line_index >= dist {
                    for tup in rt_to_lb_group[line_index - dist].iter().by_ref() {
                        let x = tup.0;
                        let y = tup.1;
                        let dist1 = manhattan_dist(line[i].0, line[i].1, x, y);
                        let dist2 = manhattan_dist(line[j].0, line[j].1, x, y);
                        if dist1 == dist && dist == dist2 {
                            let mut new_ans =
                                vec![(line[i].0, line[i].1), (line[j].0, line[j].1), (x, y)];
                            new_ans.sort();
                            ans_set.insert(new_ans);
                        }
                    }
                }
                if line_index + dist < rt_to_lb_group.len() {
                    for tup in rt_to_lb_group[line_index + dist].iter().by_ref() {
                        let x = tup.0;
                        let y = tup.1;
                        if manhattan_dist(line[i].0, line[i].1, x, y) == dist
                            && manhattan_dist(line[j].0, line[j].1, x, y) == dist
                        {
                            let mut new_ans =
                                vec![(line[i].0, line[i].1), (line[j].0, line[j].1), (x, y)];
                            new_ans.sort();
                            ans_set.insert(new_ans);
                        }
                    }
                }
            }
        }
    }

    for (line_index, line) in rb_to_lt_group.iter().by_ref().enumerate() {
        if line.len() < 2 {
            continue;
        }
        for i in 0..line.len() - 1 {
            for j in i + 1..line.len() {
                let dist = manhattan_dist(line[i].0, line[i].1, line[j].0, line[j].1);
                if line_index >= dist {
                    for tup in rb_to_lt_group[line_index - dist].iter().by_ref() {
                        let x = tup.0;
                        let y = tup.1;
                        let dist1 = manhattan_dist(line[i].0, line[i].1, x, y);
                        let dist2 = manhattan_dist(line[j].0, line[j].1, x, y);
                        if dist1 == dist && dist == dist2 {
                            let mut new_ans =
                                vec![(line[i].0, line[i].1), (line[j].0, line[j].1), (x, y)];
                            new_ans.sort();
                            ans_set.insert(new_ans);
                        }
                    }
                }
                if line_index + dist < rb_to_lt_group.len() {
                    for tup in rb_to_lt_group[line_index + dist].iter().by_ref() {
                        let x = tup.0;
                        let y = tup.1;
                        if manhattan_dist(line[i].0, line[i].1, x, y) == dist
                            && manhattan_dist(line[j].0, line[j].1, x, y) == dist
                        {
                            let mut new_ans =
                                vec![(line[i].0, line[i].1), (line[j].0, line[j].1), (x, y)];
                            new_ans.sort();
                            ans_set.insert(new_ans);
                        }
                    }
                }
            }
        }
    }
    println!("{:?}", ans_set.len());
}