これは重複組合せを生成する問題です。PowerShellの関数はほぼジェネレータなので、簡単に生成できます。
22秒かかりました。
PowerShellのシリーズはここまでです。
function fold($f, $x0) {
begin { $x = $x0 }
process { $x = &$f $x $_ }
end { $x }
}
function pow($n, $e) {
return 1..$e | fold { $args[0] * $n } 1
}
function digits($n) {
while($n -gt 0) {
$r = $n % 10
$r
$n = ($n - $r) / 10
}
}
function number($a) {
$a | fold { $args[0] * 10 + $args[1] } 0
}
function repeated_combinations($a, $n) {
if($n -eq 1) {
$a
}
else {
foreach($k in 0..($a.length-1)) {
$e = $a[$k]
repeated_combinations $a[$k..($a.length-1)] ($n - 1) |
foreach { ,(@($e) + $_) }
}
}
}
function calc_limit($E) {
for($n = 1; $n * $pows[9] -ge (pow 10 $n); ++$n) {
}
$n
}
function sum_pows($a) {
($a | foreach { $pows[$_] } | measure -sum).sum
}
function sort_by_digits($n) {
number (digits $n | sort)
}
function matches($a) {
$m = number $a
$n = sort_by_digits (sum_pows $_)
$m -eq $n
}
$watch = New-Object System.Diagnostics.Stopwatch
$watch.Start();
$E = 5
$pows = 0..9 | foreach { pow $_ $E }
$L = calc_limit $E
(repeated_combinations (0..9) $L | where { matches $_ } |
foreach { sum_pows $_ } | measure -sum).sum - 1
$watch.Stop();
$watch.Elapsed.TotalMilliSeconds / 1000