Kawazoe(@riverplus)さんのCodeIQの問題です。
元の問題(PDF)がリンク切れしてしまいましたが、
こちらから問題を見ることができます。解答もあります。
->https://oraclesqlpuzzle.ninja-web.net/kyoupro-old/kyoupro-04-003.html
kawazoeさんの解説がありました。
->https://riverplus.hatenablog.com/entry/2015/09/27/015510
こちらにも情報があります。
->https://posfie.com/@riverplus/p/3ZrX6bb
テストケースはあちこちから拾い集めたようです。
ある数を連続する二つ以上の数の和で表す方法がいくつかあったとき、
それぞれの連続する数の最小の数の和を求める問題です。
「連続する正の整数の和」の類題ですが、数字がけた違いに大きいです。
ある数を n、連続する数の最大値を y、最小値を x とすると 2n=(x+y)(y-x+1)、
素因数分解するよりも m1=y-x+1、m2=x+yとし、
m1=1,2,3...(m1<=sqrt(2n)) に対し m1*m2=2*n となる整数 m2 を求め、
x=(m2-m1+1)/2で x を求める方が簡単そうです。
m1,m2のどちらかが奇数(m1+m2が奇数)という条件が必要です。
#julia ver 1.41,1.53,1.85,1.12.1
function solve(n,a)
sum = 0
for i in 2 : Int(floor(sqrt(2*n)))
(d,m) = divrem(2*n,i)
if m == 0 && mod(i+d,2) == 1
sum += div(d-i+1,2)
end
end
s = a == sum ? "ok " : "no "
println(s,sum)
end
solve(15,12)
solve(18,8)
solve(105,139)
solve(256,0)
solve(945,1698)
solve(9999999967,4999999983)
solve(10000000000,2505942121)
Prologも同じ方針です。
%SWI-Prolog ver 7.42,7.64,9.29
%:-initialization(start). %ideone,Online Prolog Compiler
%start.
fn(N,T,T,R,R).
fn(X,T,I,R1,R):-
divmod(X,I,D,M),Y is (I+D) mod 2,
((M =:= 0,Y =:= 1)->R2 is R1+ (D-I+1) div 2;R2=R1),I1 is I+1,fn(X,T,I1,R2,R).
solve(N,R):-X is N*2,T is 1 + floor(sqrt(X)),fn(X,T,2,0,R),!.
start:-f(N,A),(solve(N,R)->(R==A->Str=" ok ";Str=" no ");
write(fail)),write(" "),write(Str),writeln(N->R),fail.
start.
f(15,12).
f(18,8).
f(105,139).
f(256,0).
f(945,1698).
f(9999999967,4999999983).
f(10000000000,2505942121).