非过剩数之和

作者:Shlomi Fish

http://projecteuler.net/problem=23

如果一个数的所有真因数之和等于它本身,则该数被称为完全数。例如,28 的真因数之和为 1 + 2 + 4 + 7 + 14 = 28,这意味着 28 是一个完全数。

如果一个数 n 的所有真因数之和小于 n,则该数被称为亏数;如果该和大于 n,则该数被称为过剩数。

由于 12 是最小的过剩数,1 + 2 + 3 + 4 + 6 = 16,因此可以写成两个过剩数之和的最小数字是 24。通过数学分析,可以证明所有大于 28123 的整数都可以写成两个过剩数之和。然而,即使已知不能表示为两个过剩数之和的最大数小于此上限,但通过分析也无法进一步降低此上限。

求所有不能写成两个过剩数之和的正整数之和。

基于:https://bitbucket.org/shlomif/project-euler/src/aa5eecd18f0825901afeb3c54dcda0da79ac3576/project-euler/23/euler-23-4.pl?at=default

源代码:prob023-shlomif.pl

use v6;

my @divisors_sums;
@divisors_sums[1] = 0;

my $MAX = 28_123;
for (1 .. ($MAX +> 1)) -> $div {
    loop (my $prod = ($div +< 1); $prod <= $MAX; $prod += $div) {
        @divisors_sums[$prod] += $div;
    }
}

# Memoized.
#
my @is_abundant_sum;

my @abundants;
my $total = 0;
for (1 .. $MAX) -> $num {
    if @divisors_sums[$num] > $num {
        @abundants.push($num);
        # The sub { ... } and return are a workaround for the fact that Rakudo
        # Perl 6 does not have last LABEL yet.
        my $c = sub {
            for @abundants -> $i {
                if ((my $s = $i + $num) > $MAX) {
                    return;
                }
                else {
                    if (! @is_abundant_sum[$s]) {
                        $total += $s;
                        @is_abundant_sum[$s] = True;
                    }
                }
            }
        };

        $c();
    }
}

say ((((1 + $MAX) * $MAX) +> 1)-$total);