この問題は6の剰余で分類すると速いです。なぜなら、12以上の6の倍数はすべて過剰数だからです。
144秒かかりました。
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 factorize($n, $p0 = 2) {
if($n -gt 1) {
for($p = $p0; $p * $p -le $n; ++$p) {
if($n % $p -eq 0) {
$e, $m = div_pow $n $p
,@($p, $e)
factorize $m ($p + 1)
return
}
}
,@($n, 1)
}
}
function pow($p, $e) {
$y = 1
for($k = 0; $k -lt $e; ++$k) {
$y *= $p
}
$y
}
function is_abundant($n) {
function f($x) {
$p, $e = $x
1..$e | fold { $args[0] * $p + 1 } 1
}
$fs = factorize($n)
if($fs[0].GetType().Name -eq "Int32") {
$fs = ,$fs
}
$a = $fs | fold { $args[0] * (f $args[1]) } 1
$b = $fs | fold { $args[0] * (pow $args[1][0] $args[1][1]) } 1
$a -gt $b * 2
}
$watch = New-Object System.Diagnostics.Stopwatch
$watch.Start();
$L = 28123
$g = 1..6 | foreach { ,@() }
foreach($n in 2..$L) {
if(is_abundant $n) {
$r = $n % 6
$g[$r] += $n
}
}
$a = 0..$L | foreach { 1 }
foreach($r in 0..5) {
if($g[$r].length -gt 0) {
$head = $g[$r][0]
for($k = $head + 12; $k -le $L; $k += 6) {
$a[$k] = 0
}
}
foreach($r1 in 1..5) {
$r2 = ($r - $r1 + 6) % 6
if($r2 -gt $r1) { continue }
foreach($p in $g[$r1]) {
if($p -gt $L) {
break
}
foreach($q in $g[$r2]) {
if($p + $q -gt $L) {
break
}
$a[$p+$q] = 0
}
}
}
}
(1..$L | where { $a[$_] -eq 1 } | measure -sum).sum
$watch.Stop();
$watch.Elapsed.TotalMilliSeconds / 1000