Problem:
Score : 400 points

Problem Statement

You are given an integer N. Among the divisors of N! (= 1 \times 2 \times ... \times N), how many Shichi-Go numbers (literally "Seven-Five numbers") are there?

Here, a Shichi-Go number is a positive integer that has exactly 75 divisors.

Note

When a positive integer A divides a positive integer B, A is said to a divisor of B.
For example, 6 has four divisors: 1, 2, 3 and 6.

Constraints

1 \leq N \leq 100

N is an integer.

Input

Input is given from Standard Input in the following format:

N

Output

Print the number of the Shichi-Go numbers that are divisors of N!.

Sample Input 1

9

Sample Output 1

0

There are no Shichi-Go numbers among the divisors of 9! = 1 \times 2 \times ... \times 9 = 362880.

Sample Input 2

10

Sample Output 2

1

There is one Shichi-Go number among the divisors of 10! = 3628800: 32400.

Sample Input 3

100

Sample Output 3

543

Solution in OCaml (4.02.3) (judge verdict: Accepted)

open Printf open Scanf
module Lib = struct
  let i32,i64,ist = Int64.(to_int,of_int,to_string)
  let (+$) = (+) let (-$) = (-) let (/$) = (/) let ( *$) = ( * ) let (%$) = (mod)
  let labs = Int64.abs
  let (+),(-),( * ),(/),(mod),(%) = Int64.(add,sub,mul,div,rem,rem)
  let (+=) r v = r := !r + v
  let (-=) r v = r := !r - v
  let ( *= ) r v = r := !r * v
  let (/=) r v = r := !r / v
  let (%=) r v = r := !r % v
  let max_i64,min_i64 = Int64.(max_int,min_int)
  (* math *)
  let ceildiv p q = (p+q-1L) / q
  let rec gcd m n = match m,n with | m,0L -> m | m,n -> gcd n (m mod n)
  let lcm m n = m / gcd m n * n
  module I64_infix = struct
    let (land),(lor),(lxor),lnot,(lsl),(lsr),(asr) =
      let open Int64 in
      (logand),(logor),(logxor),lognot,
      (fun u v -> shift_left u (i32 v)),
      (fun u v -> shift_right u (i32 v)),
      (fun u v -> shift_right_logical u (i32 v))
  end
  (* input *)
  let input_i64_array n = Array.init (i32 n) (fun _ -> Scanf.scanf " %Ld" (fun v -> v))
  let get_i64 _ = Scanf.scanf " %Ld" (fun v -> v)
  let get_2_i64 _ = Scanf.scanf " %Ld %Ld" (fun u v -> u,v)
  let get_3_i64 _ = Scanf.scanf " %Ld %Ld %Ld" (fun u v w -> u,v,w)
  let get_4_i64 _ = Scanf.scanf " %Ld %Ld %Ld %Ld" (fun u v w x -> u,v,w,x)
  let get_5_i64 _ = Scanf.scanf " %Ld %Ld %Ld %Ld %Ld" (fun u v w x y -> u,v,w,x,y)
  let i32_get_int _ = Scanf.scanf " %d" (fun v -> v) let i32_get_2_ints _ = Scanf.scanf " %d %d" (fun u v -> u,v) let i32_get_3_ints _ = Scanf.scanf " %d %d %d" (fun u v w -> u,v,w) let i32_get_4_ints _ = Scanf.scanf " %d %d %d %d" (fun u v w x -> u,v,w,x) let i32_get_5_ints _ = Scanf.scanf " %d %d %d %d %d" (fun u v w x y -> u,v,w,x,y)
  (* utils *)
  external id : 'a -> 'a = "%identity"
  let ( *< ) f g x = f (g x)
  let ( *> ) f g x = g (f x)
  let rv f p q = f q p (* ex. 24 |> rv (/) 6 *)
  let alen a = i64 @@ Array.length a
  let llen l = i64 @@  List.length l
  let string_of_list ?(separator=" ") f ls = ls |> List.map f |> String.concat separator
  let string_of_array ?(separator=" ") f a = a |> Array.to_list |> string_of_list ~separator f
  let char_list_of_string str = let rec f0 i a = if i<0 then a else f0 (i-$1) (str.[i]::a) in f0 (String.length str -$ 1) []
  let string_of_char_list ls = List.fold_left (fun u v -> u ^ (String.make 1 v)) "" ls
  let fail _ = failwith "fail"
  let dx,dy = [|1;0;-1;0|],[|0;1;0;-1|]
  let range l r = let ls = ref [] in for i=i32 l to i32 r do ls := i :: !ls done;!ls |> List.rev
  let cartesian_product u v = u |> List.map (fun p -> List.map (fun q -> p,q) v) |> List.flatten
  let shuffle a = Array.sort (fun _ _ -> (Random.int 3) -$ 1) a
  let binary_search ng ok f = let d = if ng < ok then 1L else -1L in
    let rec f0 ng ok =
      if labs (ok - ng) <= 1L then ok
      else let mid = ng + (ok - ng) / 2L in if f mid then f0 ng mid else f0 mid ok
    in f0 (ng-1L*d) (ok+1L*d)
  let lower_bound a v = binary_search 0L (alen a - 1L) (fun i -> a.(i32 i) >= v)
  let upper_bound a v = binary_search 0L (alen a - 1L) (fun i -> a.(i32 i) >  v)
  let equal_range a v = lower_bound a v, upper_bound a v (* #=snd-fst *)
  let rec fix f x = f (fix f) x
  let fix_memo ?(size=10000) f x =
    let tb = Hashtbl.create ~random:true size in
    let rec f0 x =
      try Hashtbl.find tb x with
      | Not_found -> (let v = f f0 x in Hashtbl.add tb x v; v)
    in f0 x
  (* imperative *)
  let rep f t ?(stride=1L) fbod = let i = ref f in while !i <= t do fbod !i; i := !i + stride done
  let repb f t ?(stride=1L) fbod = let i,c = ref f,ref true in while !i <= t && !c do
    match fbod !i with | `Break -> c := false | `Ok -> i := !i + stride done
  let repm f t ?(stride=1L) m0 fbod =
    let i,c,m = ref f,ref true,ref m0 in
    while !i<=t && !c do match fbod !m !i with
    | `Break -> c := false | `Break_m m' -> (c := false; m := m') | `Ok m' -> m := m'; i := !i + stride done; !m
  let repi f t ?(stride=1) fbod = let i = ref f in while !i <= t do fbod !i; i := !i +$ stride done
  let repib f t ?(stride=1) fbod = let i,c = ref f,ref true in while !i <= t && !c do
    match fbod !i with | `Break -> c := false | `Ok -> i := !i +$ stride done
  let repim f t ?(stride=1) m0 fbod =
    let i,c,m = ref f,ref true,ref m0 in
    while !i<=t && !c do match fbod !m !i with
    | `Break -> c := false | `Break_m m' -> (c := false; m := m') | `Ok m' -> m := m'; i := !i +$ stride done; !m
  let rep_rev f t ?(stride=1L) fbod = rep t f ~stride @@ fun v -> fbod @@ f + t - v
  let repb_rev f t ?(stride=1L) fbod = repb t f ~stride @@ fun v -> fbod @@ f + t - v
  let repm_rev f t ?(stride=1L) m0 fbod = repm f t ~stride m0 @@ fun u v -> fbod u @@ f + t - v
  let repi_rev f t ?(stride=1) fbod = repi t f ~stride @@ fun v -> fbod @@ f +$ t -$ v
  let repib_rev f t ?(stride=1) fbod = repib t f ~stride @@ fun v -> fbod @@ f +$ t -$ v
  let repim_rev f t ?(stride=1) m0 fbod = repim f t ~stride m0 @@ fun u v -> fbod u @@ f +$ t -$ v
  (* output *)
  let print_list_mle f ls = string_of_list f ls |> print_endline
  let print_array_mle f a = string_of_array f a |> print_endline
  let print_list f ls = ls |> List.iter (fun v -> printf "%s " @@ f v); print_newline ()
  let print_array f a = a |> Array.iter (fun v -> printf "%s " @@ f v); print_newline ()
  (* debug *)
  let dump_2darr f a = a |> Array.iter (fun b -> print_array f b)
  let dump_i64_list ls = print_list ist ls
  let dump_i64_array a = print_array ist a
end open Lib open Array

let () =
  let n = i32_get_int 0 in
  let r = [|0;0;0;0;0;0;0;0;0;1;1;1;1;2;2;3;3;3;3;8;8;11;11;11;11;14;14;32;32;35;35;35;35;42;42;42;42;49;49;49;49;49;49;75;75;86;86;86;86;86;86;123;123;131;131;131;131;148;148;153;153;170;170;170;170;170;170;227;227;227;227;227;227;250;250;323;323;324;324;324;324;354;354;354;354;384;384;384;384;384;391;491;491;529;529;529;529;529;529;543;|]
  in
  printf "%d\n" r.(n-$1)
(*
  let sieve n = (* includes 0, O(nloglogn) *)
  let n = i32 n in
  let prime = Array.make (n+$1) true in
  prime.(0) <- false;
  prime.(1) <- false;
  for i=2 to n do
    if prime.(i) then let j = ref @@ i*$2 in
    while !j <= n do prime.(!j) <- false; j := !j +$ i; done
  done; prime

  let divisors_1_to_n n = (* O(nloglogn) *)
    let res = Array.make (n+$1) [] in
    for i=1 to n do
      let j = ref @@ i in
      while !j <= n do res.(!j) <- i::res.(!j); j := !j +$ i; done;
      res.(i) <- List.rev res.(i)
    done; res
    let factors n =
      let m,r = ref n,ref [] in
      rep 2L (n/2L) (fun i ->
        if !m mod i = 0L then (
          let k = ref 0L in
          while !m mod i = 0L do
            k += 1L; m /= i;
          done;
          r := (i,!k) :: !r));
      if !m>1L then (!m,1L)::!r else !r
let () =
  let primes =
    let a = sieve 108L in
    fold_left (fun (l,i) v -> if v then ((i)::l,i+1L) else (l,i+1L)) ([],0L) a
    |> fst |> of_list
  in
  let divs = divisors_1_to_n 108 in
  (* let n = get_i64 0 in *)
  rep 1L 100L (fun n ->
  let nprimes = make 108 0L in
  rep 1L n (fun i ->
    let facts = factors i in
    (* print_list (fun (n,k) -> sprintf "(%Ld,%Ld)" n k) facts; *)
    List.iter (fun (n,k) -> nprimes.(i32 n) <- nprimes.(i32 n) + k) facts;
  );
  (* print_array ist nprimes; *)
  let res = ref 0L in
  (* 3,5,5 *)
  rep 1L n (fun i ->
    rep (i+1L) n (fun j ->
      rep (j+1L) n (fun k ->
        let h = [3L,5L,5L;5L,3L,5L;5L,5L,3L] in
        let i,j,k = nprimes.(i32 i)+1L,nprimes.(i32 j)+1L,nprimes.(i32 k)+1L in
        List.iter (fun (p,q,r) ->
          if p<=i && q<=j && r<=k then (
            res += 1L;
            (* (i-p+1L)*(j-q+1L)*(k-r+1L) *)
            (* let h = [3L,15L;15L,3L] in
            let i,j = nprimes.(i32 i)+1L,nprimes.(i32 j)+1L in
            let f = ref false in
            List.iter (fun (p,q) ->
              if p<=i && q<=j then f:=true
              (* (i-p+1L)*(j-q+1L) *)
            ) h;
            if not !f then res += 1L; *)
          )
        ) h
      )
    )
  );
  (* 5,15 *)
  rep 1L n (fun i ->
    rep (i+1L) n (fun j ->
      let h = [5L,15L;15L,5L] in
      let i,j = nprimes.(i32 i)+1L,nprimes.(i32 j)+1L in
      List.iter (fun (p,q) ->
        if p<=i && q<=j then res += 1L
        (* (i-p+1L)*(j-q+1L) *)
      ) h
    )
  );
  (* 3,25 *)
  rep 1L n (fun i ->
    rep (i+1L) n (fun j ->
      let h = [3L,25L;25L,3L] in
      let i,j = nprimes.(i32 i)+1L,nprimes.(i32 j)+1L in
      List.iter (fun (p,q) ->
        if p<=i && q<=j then res += 1L
        (* (i-p+1L)*(j-q+1L) *)
      ) h
    )
  );
  (* 75 *)
  rep 1L n (fun i ->
    if nprimes.(i32 i)+1L >= 75L then res += 1L
  );
  printf "%Ld;" !res
  )








 *)