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: Wrong Answer)

use std::cmp::{max, min};
use std::collections::BTreeSet;

const X: usize = 400;
const W: usize = X * 2;

fn main() {
    let (r, w) = (std::io::stdin(), std::io::stdout());
    let mut sc = IO::new(r.lock(), w.lock());

    let h: usize = sc.read();
    let w: usize = sc.read();

    let board: Vec<Vec<_>> = (0..h).map(|_| sc.chars()).collect();
    let mut board2 = vec![vec![' '; w]; h];
    for i in 0..h {
        for j in 0..w {
            board2[i][j] = board[i][w - 1 - j];
        }
    }

    let ans1 = solve(&board);
    let ans2 = solve(&board2);
    let ans3 = solve2(&board);
    // let ans4 = solve2(&board2);

    let ans = ans1 + ans2 + ans3;
    println!("{}", ans);
}

fn solve2(board: &Vec<Vec<char>>) -> usize {
    let h = board.len();
    let w = board[0].len();
    let mut ans = 0;
    for i in 0..h {
        for j in 0..w {
            if board[i][j] != '#' {
                continue;
            }
            for d in 1..X {
                if i + d >= h || j + d >= w {
                    break;
                }
                if board[i + d][j + d] != '#' {
                    continue;
                }

                if j >= d && i + d < h && board[i + d][j - d] == '#' {
                    ans += 1;
                }
                if i >= d && j + d < w && board[i - d][j + d] == '#' {
                    ans += 1;
                }
                if j + 2 * d < w && board[i][j + 2 * d] == '#' {
                    ans += 1;
                }
                if i + 2 * d < h && board[i + 2 * d][j] == '#' {
                    ans += 1;
                }
            }
        }
    }
    ans
}

fn solve(s: &Vec<Vec<char>>) -> usize {
    let mut board = vec![vec!['.'; W]; W];
    for i in 0..s.len() {
        for j in 0..s[i].len() {
            board[i + X][j] = s[i][j];
        }
    }

    let mut sum = vec![vec![0; W + 1]; W];
    for i in 0..W {
        for j in 0..W {
            if i + j >= W {
                break;
            }
            sum[i][j + 1] = sum[i][j] + if board[i + j][j] == '#' { 1 } else { 0 };
        }
    }

    let mut ans = 0;
    for index in 0..W {
        for i in 0..W {
            if index + i >= W {
                break;
            }
            if board[index + i][i] != '#' {
                continue;
            }
            for j in (i + 1)..W {
                if index + j >= W {
                    break;
                }
                if board[index + j][j] != '#' {
                    continue;
                }

                let d = j - i;
                if index >= 2 * d {
                    ans += sum[index - 2 * d][min(j + d, W)] - sum[index - 2 * d][j + 1];
                }
                if index + 2 * d < W {
                    ans += sum[index + 2 * d][i] - sum[index + 2 * d][max(i + 1, d) - d];
                }
            }
        }
    }
    ans
}

pub struct IO<R, W: std::io::Write>(R, std::io::BufWriter<W>);

impl<R: std::io::Read, W: std::io::Write> IO<R, W> {
    pub fn new(r: R, w: W) -> Self {
        IO(r, std::io::BufWriter::new(w))
    }
    pub fn write<S: ToString>(&mut self, s: S) {
        use std::io::Write;
        self.1.write(s.to_string().as_bytes()).unwrap();
    }
    pub fn read<T: std::str::FromStr>(&mut self) -> T {
        use std::io::Read;
        let buf = self
            .0
            .by_ref()
            .bytes()
            .map(|b| b.unwrap())
            .skip_while(|&b| b == b' ' || b == b'\n' || b == b'\r' || b == b'\t')
            .take_while(|&b| b != b' ' && b != b'\n' && b != b'\r' && b != b'\t')
            .collect::<Vec<_>>();
        unsafe { std::str::from_utf8_unchecked(&buf) }
            .parse()
            .ok()
            .expect("Parse error.")
    }
    pub fn vec<T: std::str::FromStr>(&mut self, n: usize) -> Vec<T> {
        (0..n).map(|_| self.read()).collect()
    }
    pub fn chars(&mut self) -> Vec<char> {
        self.read::<String>().chars().collect()
    }
}