问题描述
我正在kattis上处理此smallest multiple problem。
我已经用Python和C ++解决了它,但是现在我想做OCaml。
这是我的代码:
open Printf;;
let rec gcd (a : int64) (b : int64) : int64 =
if not (Int64.unsigned_compare b 0L > 0) then
a
else
gcd b (Int64.unsigned_rem a b);;
try
while true;
do
let line = read_line ()
in
if String.length line > 0 then
let (nums : int64 list) = List.map (fun (s:string) : (int64) ->
(Int64.of_string (Char.escaped '0' ^ Char.escaped 'u' ^ s ))) (String.split_on_char ' ' line)
in
let rec reduce (li : int64 list) (init : int64) : (int64) =
match li with
| [] -> init
| head :: tail -> reduce tail ( Int64.unsigned_div (Int64.mul head init) (gcd head init) )
in
print_string ( Int64.to_string (reduce nums 1L) ^ "\n")
else
raise End_of_file
done;
with End_of_file -> ();;
我可以通过第一个案例,但是第二个(也是最后一个)案例会导致错误的答案。这很奇怪,因为我的前两份不同语言的论文中我的逻辑是相同的。
我的猜测是我错误地打印了无符号的64位整数:
print_string ( Int64.to_string (reduce nums 1L) ^ "\n")
之前,我尝试过:
printf "%Lu\n" (reduce nums 1L)
u,n,l,L,or N: convert an integer argument to unsigned decimal. Warning: n,and N are used for scanf,and should not be used for printf.
我实际上并不认为此警告与我的情况有关,但我仍然感到疲倦。
有什么想法吗?感谢您的阅读!
解决方法
您的代码对我有用。您可以考虑从头开始重新启动OCaml,然后复制/粘贴上面的代码。那就是我所做的,对我有用。
. . .
with End_of_file -> ();;
2 3 5
30
1 2 3 4
12
399 772 163 959 242
832307365428
- : unit = ()
#
我有一个64位系统,物有所值。即max_int对我来说是4611686018427387903。
,466941151233371166不是任何输入的倍数,因此显然是错误的。输入数字相当大,所以我猜您只是整数溢出。另一方面,您的C ++代码说1,这也不是任何数字的倍数,而且显然也是错误的。
我看到一个可能是问题的地方
( Int64.unsigned_div (Int64.mul head init) (gcd head init) )
在处理输入时,init
越来越大,然后将其乘以下一个数字。仅在将其除以GCD之后。在该步骤中,它暂时超过了64位,您会丢失一些位。
根据GCD的定义,head和init都可以被它整除。那么,为什么不将其中之一乘以GCD呢?
(Int64.mul init (Int64.unsigned_div head (gcd head init)))
这样,您的中间数永远不会比结果大,并且接近64位限制的结果仍然会产生正确的结果。