エラトステネスのふるい的に約数の和を求めるだけですね。
function fold($f, $x0) {
begin { $x = $x0 }
process { $x = &$f $x $_ }
end { $x }
}
function div_pow($n, $d) {
$e = 0
while($n % $d -eq 0) {
++$e
$n /= $d
}
($e, $n)
}
function sum_divs($n) {
$a = 0..$n
$b = $a | foreach { 1 }
foreach($p in 2..$n) {
if($p * $p -gt $n) {
break
}
elseif($a[$p] -eq $p) {
for($k = $p; $k -le $n; $k += $p) {
$e, $a[$k] = div_pow $a[$k] $p
$b[$k] *= (1..$e | fold { $args[0] * $p + 1 } 1)
}
}
}
foreach($k in 2..$n) {
if($a[$k] -ne 1) {
$b[$k] *= $a[$k] + 1
}
}
0..$n | foreach { $b[$_] - $_ }
}
function gen_amicables($n) {
$d = sum_divs $n
foreach($k in 2..$n) {
$m = $d[$k]
if($m -lt $k -and $d[$m] -eq $k) {
$k, $m
}
}
}
(gen_amicables 10000 | measure -sum).sum