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

Problem 12

1 2 3 4 5 6 …

の偶数を2で割って、

1 1 3 2 5 3 …

隣同士を掛け合わせると、

1 3 6 10 15 …

これは三角数の列になっています。2番目の列の約数の数を求めると、

1 1 2 2 2 2 …

隣同士を掛け合わせて、

1 2 4 4 4 …

これが対応する三角数の約数の数になっています(2番目の列の隣同士は互いに素だから)。こうすれば速く計算できます。これで20分でした。

@echo off

call :get_time
set /a t0 = %ERRORLEVEL%
set /a L = 500
set /a n = 2
set /a prev_num = 1
:loop
    set /a r = %n% %% 2
    if %r% == 0 (
        set /a m = %n% / 2
    ) else (
        set /a m = %n%
    )
    call :num_divs %m%
    set /a num = %ERRORLEVEL%
    set /a mul_num = %prev_num% * %num%
    set /a n += 1
    set /a prev_num = %num%
    if %mul_num% LSS %L% goto :loop
set /a nt = (%n% - 2) * (%n% - 1) / 2
echo %nt%
call :get_time
set /a t = %ERRORLEVEL% - %t0%
echo %t:~0,-2%.%t:~-2%s
exit /b 0

:num_divs
    setlocal
    set /a num = 1
    set /a n = %1
    set /a p = 2
    :loop_num_divs
        set /a e = 0
        :loop_num_divs2
            set /a r = %n% %% %p%
            if %r% == 0 (
                set /a e += 1
                set /a n /= %p%
                goto :loop_num_divs2
            )
        
        set /a num *= %e% + 1
        if %n% == 1 exit /b %num%
        set /a p += 1
        set /a p_sq = %p% * %p%
        if %n% GEQ %p_sq% goto :loop_num_divs
        set /a num *= 2
        exit /b %num%

:get_time
    setlocal
    set t=%TIME%
    set /a h = %t:~0,2%
    set /a m = 1%t:~3,2% %% 100
    set /a s = 1%t:~6,2% %% 100
    set /a ss = 1%t:~-2% %% 100
    set /a ret = ((%h% * 60 + %m%) * 60 + %s%) * 100 + %ss%
    exit /b %ret%