Problem:
Score : 300 points

Problem Statement

You are given N real values A_1, A_2, \ldots, A_N.
Compute the number of pairs of indices (i, j)
such that i < j and the product A_i \cdot A_j is integer.

Constraints

2 \leq N \leq 200\,000

0 < A_i < 10^4

A_i is given with at most 9 digits after the decimal.

Input

Input is given from Standard Input in the following format.

N
A_1
A_2
\vdots
A_N

Output

Print the number of pairs with integer product A_i \cdot A_j (and i < j).

Sample Input 1

5
7.5
2.4
17.000000001
17
16.000000000

Sample Output 1

3

There are 3 pairs with integer product:

7.5 \cdot 2.4 = 18

7.5 \cdot 16 = 120

17 \cdot 16 = 272

Sample Input 2

11
0.9
1
1
1.25
2.30000
5
70
0.000000001
9999.999999999
0.999999999
1.000000001

Sample Output 2

8

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

use std::{
  io::{self, Write},
  str,
};

struct Scanner<R> {
  reader: R,
  buf_str: Vec<u8>,
  buf_iter: str::SplitAsciiWhitespace<'static>,
}

impl<R: io::BufRead> Scanner<R> {
  fn new(reader: R) -> Self {
      Self {
          reader,
          buf_str: Vec::new(),
          buf_iter: "".split_ascii_whitespace(),
      }
  }

  fn next<T: str::FromStr>(&mut self) -> T {
      loop {
          if let Some(token) = self.buf_iter.next() {
              return token.parse().ok().expect("Failed parse");
          }
          self.buf_str.clear();
          self.reader.read_until(b'\n', &mut self.buf_str).expect("Failed read");
          self.buf_iter = unsafe {
              let slice = str::from_utf8_unchecked(&self.buf_str);
              std::mem::transmute(slice.split_ascii_whitespace())
          }
      }
  }

  fn next_line(&mut self) -> String {
    let mut line = String::new();
    self.reader.read_line(&mut line).expect("Failed to read line");
    line.trim().to_string()
}
}

fn main() {
  let (stdin, stdout) = (io::stdin(), io::stdout());
  let mut cin = Scanner::new(stdin.lock());
  let mut cout = io::BufWriter::new(stdout.lock());

  let n: usize = cin.next();
  let mut cnt = vec![vec![0; 100]; 100];
  let mut p2 = vec![1; 10];
  let mut p5 = vec![1; 10];
  for i in 1..10 {
    p2[i] = p2[i - 1] * 2;
    p5[i] = p5[i - 1] * 5;
  }
  for _ in 0..n {
    let s: Vec<char> = cin.next_line().chars().collect();
    let mut mid = s.len();
    for i in 0..s.len() {
      if s[i] == '.' {
        mid = i;
        break;
      }
    }
    let x: u64;
    let y: u64;
    let l: usize;
    if mid == s.len() {
      let s: String = s.iter().collect();
      x = s.parse().ok().unwrap();
      y = 0;
      l = 0;
    } else {
      let u: String = (&s[0..mid]).iter().collect();
      let v: String = (&s[mid + 1..]).iter().collect();
      x = u.parse().ok().unwrap();
      y = v.parse().ok().unwrap();
      l = v.len();
    }
    let p10 = p2[l] * p5[l];
    let g = gcd(x * p10 + y, p10);
    let a = (x * p10 + y) / g;
    let mut b = p10 / g;
    let mut b2 = 0;
    let mut b5 = 0;
    while b % 2 == 0 {
      b /= 2;
      b2 += 1;
    }
    while b % 5 == 0 {
      b5 += 1;
      b /= 5;
    }
    for a2 in 0..10 {
      for a5 in 0..10 {
        let v = p2[a2] * p5[a5];
        if a % v == 0 {
          cnt[b2 * 10 + b5][a2 * 10 + a5] += 1;
        }
      }
    }
  }
  let mut ret: u64 = 0;
  for i in 0..100 {
    for j in 0..i {
      ret += cnt[i][j] * cnt[j][i];
    }
  }
  ret += cnt[0][0] * (cnt[0][0] - 1) / 2;
  writeln!(cout, "{}", ret).ok();
}

fn gcd(a: u64, b: u64) -> u64 {
  if b == 0 {
    a
  } else {
    gcd(b, a % b)
  }
}