Windows PowerShellでProject Euler(30)

Problem 23

この問題は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