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();
    let mut rt_to_lb_accum_sum = Vec::new();
    for i in 0..h + w - 1 {
        let mut x = 0;
        let mut y = i as i32;
        let mut line = Vec::new();
        let mut sums = vec![0];
        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] {
                line.push((x, y));
                let cur_sum = sums.last().unwrap() + 1;
                sums.push(cur_sum);
            } else {
                let cur_sum = sums.last().unwrap() + 0;
                sums.push(cur_sum);
            }
            x += 1;
            y -= 1;
        }
        rt_to_lb_group.push(line);
        rt_to_lb_accum_sum.push(sums);
    }

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

    let mut rb_to_lt_group = Vec::new();
    let mut rb_to_lt_accum_sum = 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();
        let mut sums = vec![0];
        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] {
                line.push((x, y));
                let cur_sum = sums.last().unwrap() + 1;
                sums.push(cur_sum);
            } else {
                let cur_sum = sums.last().unwrap() + 0;
                sums.push(cur_sum);
            }
            x += 1;
            y += 1;
        }
        rb_to_lt_accum_sum.push(sums);
        rb_to_lt_group.push(line);
    }

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

    let mut ans = 0;

    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 {
                    let target_accum = &rt_to_lb_accum_sum[line_index - dist];
                    let begin = std::cmp::max(0, line[i].0 - dist as i32 / 2) as usize;
                    let end = std::cmp::min(target_accum.len() as i32 - 1, line[j].0 - dist as i32 / 2 + 1) as usize;
                    ans += target_accum[end] - target_accum[begin];
                    // println!("1 s ans {0} {1} {2} {3} {4}", ans, line[i].0, line[i].1, line[j].0, line[j].1);
                    // println!("line {2} begin {0}({4}) end {1}({5}) len {3}", begin, end, line_index - dist, target_accum.len(), target_accum[begin], target_accum[end]);

                }
                if line_index + dist < rt_to_lb_group.len() {
                    let target_accum = &rt_to_lb_accum_sum[line_index + dist];
                    let begin = std::cmp::max(0, line[i].0 + dist as i32 / 2) as usize;
                    let end = std::cmp::min(target_accum.len() as i32 - 1, line[j].0 + dist as i32 / 2 + 1) as usize;
                    ans += target_accum[end] - target_accum[begin];
                    // println!("2 l ans {0} {1} {2} {3} {4}", ans, line[i].0, line[i].1, line[j].0, line[j].1);
                    // println!("line {2} begin {0}({4}) end {1}({5}) len {3}", begin, end, line_index + dist, target_accum.len(), target_accum[begin], target_accum[end]);
                }
            }
        }
    }
    // println!("{:?}", 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 {
                    let target_accum = &rb_to_lt_accum_sum[line_index - dist];
                    let begin = std::cmp::max(0, line[i].0 - dist as i32 / 2 + 1) as usize;
                    let end = std::cmp::min(target_accum.len() as i32 - 1, std::cmp::max(line[j].0 - dist as i32 / 2, 0)) as usize;
                    ans += target_accum[end] - target_accum[begin];
                    // println!("3 s ans {0} {1} {2} {3} {4}", ans, line[i].0, line[i].1, line[j].0, line[j].1);
                    // println!("3 line {2} begin {0} end {1}", begin, end, line_index - dist);
                }
                if line_index + dist < rb_to_lt_group.len() {
                    let target_accum = &rb_to_lt_accum_sum[line_index + dist];
                    let begin = std::cmp::max(0, line[i].0 + dist as i32 / 2 + 1) as usize;
                    let end = std::cmp::min(target_accum.len() as i32 - 1, std::cmp::max(line[j].0 + dist as i32 / 2, 0)) as usize;
                    ans += target_accum[end] - target_accum[begin];
                    // println!("4 l ans {0} {1} {2} {3} {4}", ans, line[i].0, line[i].1, line[j].0, line[j].1);
                    // println!("4 line {2} begin {0} end {1}", begin, end, line_index + dist);
                }
            }
        }
    }
    println!("{:?}", ans);
}


Measured memory_bytes: 8444