バッチファイルでProject Euler(53)

Problem 23


Problem 21と同じように約数の和を求めて、28123より小さい過剰数のリストを得ます。28123より小さいインデックスの配列を作って、0に初期化します。そして、全ての過剰数のペアの和を取ってその要素を1にします。
しかし、この方法は大きな配列が必要になるため、非常に遅いです。2000までで5分かかりました。

@echo off

setlocal enabledelayedexpansion
set /a N = 28123
set /a N = 2000
call :sqrt %N%
set /a L = %ERRORLEVEL%
set /a M = 500

rem // calculate prime numbers
set /a ps.size = 1
set /a ps_0 = 2
for /L %%k in (3, 2, %L%) do (
    call :is_prime %%k
    if !ERRORLEVEL! == 1 call :push_vector ps %%k
)

rem // get abundant numbers
set /a abn.size = 0
for /L %%b in (2, %M%, %N%) do (
    set /a e = %%b + %M%
    call :sieve a b %%b !e!
    set /a e_1 = !e! - 1
    for /L %%n in (%%b, 1, !e_1!) do (
        set /a k = %%n - %%b
        set /a sd = "b_!k!" - %%n
        if !sd! GTR %%n (
            set /a abn_!abn.size! = %%n
            set /a abn.size += 1
        )
    )
)
echo %abn.size%

set /a a.size = %N% + 1
call :fill a %a.size% 0
set /a max_index = %abn.size% - 1
for /L %%i in (0, 1, %max_index%) do (
    set /a n1 = "abn_%%i"
    for /L %%j in (%%i, 1, %max_index%) do (
        set /a n2 = "abn_%%j"
        set /a n3 = !n1! + !n2!
        if !n3! LEQ %N% set /a a_!n3! = 1
    )
)

set /a s = 0
for /L %%k in (1, 1, %N%) do (
    set /a e = "a_%%k"
    if !e! == 0 set /a s += %%k
)
echo %s%
exit /b 0

:sqrt
    setlocal
    set /a r = %1
    :loop_sqrt
        set /a r1 = (%r% + %1 / %r%) / 2
        if %r1% GEQ %r% exit /b %r%
        set /a r = %r1%
        goto :loop_sqrt

:is_prime
    set /a max_index = "ps.size" - 1
    for /L %%k in (0, 1, %max_index%) do (
        set /a r = %1 %% "ps_%%k"
        if !r! == 0 exit /b 0
    )
    exit /b 1

:sieve
    set /a _e = %4 - 1
    call :range %1 %3 %4
    call :fill %2 %M% 1
    set /a k = 0
    set /a p = 2
    :loop_sieve
        set /a _b = (%3 + %p% - 1) / %p% * %p%
        if %_b% == %p% set /a _b += %p%
        for /L %%k in (%_b%, %p%, %_e%) do (
            set /a i = %%k - %3
            set /a a_!i! /= %p%
            set /a _s = 1 + %p%
            set /a r = "a_!i!" %% %p%
            if !r! == 0 call :div_exp
            set /a b_!i! *= !_s!
        )
        set /a k += 1
        set /a p = "ps_%k%"
        if %p% GTR 0 (
            set /a p_sq = %p% * %p%
            if !p_sq! LSS %4 goto :loop_sieve
        )
    
    set /a M_1 = %M% - 1
    for /L %%k in (0, 1, %M_1%) do (
        set /a ak = "%1_%%k"
        if !ak! GTR 1 set /a %2_%%k *= !ak! + 1
    )
    exit /b 0

:div_exp
    :loop_div_exp
        set /a a_!i! /= %p%
        set /a _s = !_s! * %p% + 1
        set /a r = a_!i! %% %p%
        if %r% NEQ 0 exit /b 0
        goto :loop_div_exp

:sum_divs
    setlocal
    set /a s = 1
    call :sqrt %1
    set /a max = %ERRORLEVEL%
    for /L %%d in (2, 1, %max%) do (
        set /a r = %1 %% %%d
        if !r! == 0 (
            set /a s += %%d
            set /a q = %1 / %%d
            if %%d NEQ !q! set /a s += !q!
        )
    )
    exit /b %s%

:divs
    :loop_divs
        set /a q /= !d!
        set /a _s = !_s! * !d! + 1
        set /a r = !q! %% !d!
        if !r! NEQ 0 exit /b 0
        goto :loop_divs

:range
    if "%3" == "" call :range %1 0 %2 1 & exit /b 0
    if "%4" == "" call :range %1 %2 %3 1 & exit /b 0
    
    set /a max_index = (%3 - %2) / %4 - 1
    set /a %1.size = %max_index% + 1
    for /L %%i in (0, 1, %max_index%) do (
        set /a %1_%%i = %2 + %%i * %4
    )
    exit /b 0

:fill
    set /a %1.size = %2
    set /a max_index = %2 - 1
    for /L %%k in (0, 1, %max_index%) do set /a %1_%%k = %3
    exit /b 0

:push_vector
    set /a size = "%1.size"
    set /a %1_%size% = %2
    set /a %1.size += 1
    exit /b 0