11 =(1 + 2 + 3 + 4 + 5)-(1 + 2 + 3)+(6)-(4)


35

正の整数Nを指定すると、次のアルゴリズムがNに到達するために必要なステップ数を返すことがタスクになります。

  1. 最小の三角数の検索T iのようにT I  ≥Nを。対応するリストL = [1、2、...、i]を作成します。

  2. Lの項の合計がNより大きい間、リストから最初の項を削除します。

  3. Lの項の合計がNより小さい場合、iをインクリメントしてリストに追加します。ステップ2に進みます。

Nに到達するとすぐに停止します。最初のステップのみが体系的に実行されます。ステップ2と3はまったく処理されない場合があります。

以下はN = 11の例です。

例

したがって、N = 11の期待される出力は4ですです。

他の例:

  • N = 5 - T 3 = 1 + 2 + 3 = 6で始まり、 2 + 3 = 5が続きます。期待される出力: 2
  • N = 10 -ためだけ最初のステップが必要とされる 10は三角数である: T 4 = 1 + 2 + 3 + = 10 4。期待される出力: 1

最初の100個の値

下記のための結果である1≤N≤100

  1,  2,  1,  4,  2,  1,  2, 10,  2,  1,  4,  2,  6,  2,  1, 22,  8,  2, 10,  2,
  1,  2, 12,  6,  2,  4,  2,  1, 16,  2, 18, 50,  2,  6,  2,  1, 22,  6,  2,  4,
 26,  2, 28,  2,  1,  8, 30, 16,  2,  6,  4,  2, 36,  2,  1,  2,  4, 12, 40,  2,
 42, 14,  2,108,  2,  1, 46,  2,  6,  4, 50,  2, 52, 18,  2,  4,  2,  1, 56, 12,
  2, 20, 60,  4,  2, 22, 10,  2, 66,  2,  1,  4, 10, 24,  2, 40, 72,  8,  2,  6

ルール

  • 完全なプログラムまたは関数を作成して、結果を出力または返すことができます。
  • あなたがしている必要いかなる処理するために、N≤65536をミッドレンジのハードウェア上で1分未満で。
  • 十分な時間があれば、プログラム/関数、言語でネイティブにサポートされているNの値に対して理論的に機能するはずです。表示されない場合は、回答でその理由を説明してください。
  • これはコードゴルフですので、バイト単位の最短回答が勝ちです!

関連。(これについては既に知っていると思いますが、後世のために投稿するだけです)
ETHproductions

処理する必要があるNの最大値は?
ルーク

@Luke更新されたルールをご覧ください。
アーナウド

回答:


4

ゼリー29 31 バイト

ÆDµ’H+Ṛ%1$ÐḟṂ
>TḢ_@Ç}‘Ḥ
R+\ðċȯç

結果を返すモナドリンク(N = 65536は2秒未満かかります)。

オンラインでお試しください!

どうやって?

アルゴリズムの詳細説明については、Martin Enderによる素晴らしい投稿を参照してください。

ÆDµ’H+Ṛ%1$ÐḟṂ - Link 1, smallest natural number, M, that satisfies the below*, N
              - * N = T(M) - T(i) for some non-negative integer i <= M
ÆD            - divisors of N
  µ           - monadic chain separation, call that d
   ’          - increment d (vectorises)
    H         - halve (vectorises
      Ṛ       - reverse d
     +        - add (vectorises)
          Ðḟ  - filter discard if:
       %1$    -   modulo one is truthy (those which are the result of even divisors)
            Ṃ - minimum

>TḢ_@Ç}‘Ḥ - Link 2, evaluate result for non-triangular: list of T(1) to T(N), N
>         - T(i) > N
 T        - truthy indexes
  Ḣ       - head (yields the first i for which T(i) > N)
     Ç}   - call last link (1) as a monad converted to a dyad using the right argument
   _@     - subtract with reverse @rguments
       ‘  - increment
        Ḥ - double 

R+\ðċȯç - Main link: N
R       - range -> [1,2,...,N]
 +\     - reduce with addition -> [1,3,6,10,...T(N)]
   ð    - dyadic chain separation, call that t
    ċ   - count occurrences of N in t (1 if N is triangular else 0)
      ç - call last link (2) as a dyad(t, N)
     ȯ  - or

説明したアルゴリズムで作成した29バイトのフルプログラム実装は、ラップトップでN = 65536の場合に4分30分かかるため、カウントされないものと思われます。

Ṁ‘ṭµS<³µ¿
ḊµS>³µ¿
0®Ḃ‘©¤ĿÐĿL’

ステップ3ごとにwhileループを使用し、ステップ1としてそれを再利用することは、ステップ3のチェックが何もなくなるまでリストを構築してから値の最初のインデックスを見つけることを意味するため、リストの初期化で管理できる長さと同じです:

ḊµS>³µ¿
Ṁ‘ṭ
Ḥ½_.ĊR®Ḃ‘©¤ĿÐĿS€i

25

Mathematica、79バイト

Min[2#/(d=Divisors@#~Cases~_?OddQ)+d]-2⌊(2#)^.5+.5⌋+⌈Sqrt[8#+1]~Mod~1⌉&

説明

チャレンジでアルゴリズムを実装するのが面倒なので、ソリューションへのショートカットを探していました。見つけましたが、残念ながらアルゴリズムを実装するMathematicaの答えに勝るものはありません。とはいえ、これはまだ最適化されたものではなく、このアプローチやプロセスで得られた洞察のいくつかから利益を得ることができる他の言語があるかもしれません。

したがって、計算するシーケンスは次のとおりであると主張します。

f(n)= 2 *(A212652(n)-A002024(n))+ 1 + A023532(n-1)

または、nが三角数の場合はf(n)= 1で、それ以外の場合はf(n)= 2 *(A212652(n)-A002024(n)+ 1)です。

最初の式では、A023532は単にこれら2つの異なるケースをエンコードします。他の2つの配列は(プラス1)最大整数間の差であるk個の最長の分解におけるn個の連続する整数に(K-I + 1)+(K-I + 2)+ ... + K = Nと最大の整数jのように1 + 2 + ... + J <N

やや単純な言葉で、ここでは、非三角数のための答えを見つける方法です:まず、最大の三角形の数を見つけるのT jのある以下よりn個を。そして、jはステップの間に追加される最後から二番目の整数である1(追加した後ので、J + 1を、我々は超えていますN)。次に、nをできるだけ多くの(または小さい)連続した整数に分解し、これらの数値kの最大値を呼び出します。結果は単に2 *(kj)です。この直感的な理由は、分解の最大値が1つおきに1ずつ増加し、到達すると停止するためです。k

これが機能することを証明するには、次の4つのことを示す必要があります。

  1. 三角数の場合、f(n)= 1。これは、最初のステップがすべての三角形の数を単純に反復するためです。このプロセス中に正確にnをヒットした場合、作業は完了し、計算するステップは1つだけでした。
  2. 他のすべての番号については、削除ステップの後は常に終了し、挿入ステップの後は終了しません。つまり、他のすべてのf(n)は偶数です。
  3. 最初の挿入後の各挿入ステップでは、1つの数字のみを追加します。これにより、kj個のステップの後にkを含む分解に到達することが保証されます。
  4. 取得するnの最終的な分解は、常に連続した整数へのnの可能な限り長い分解です。つまり、常に合計数の中で最小の最大値を持つnの分解です。つまり、合計に追加する最後の数値は常にA212652(n)です。

(1)が真である理由はすでに示しました。次に、最初の挿入ステップ以外の挿入ステップで終了できないことを証明します(これは非三角形の数値では発生しません)。

挿入ステップで終了し、合計に値pを追加した後にnに達したとします。つまり、この挿入手順の前は、値はnp(一度に複数の値を追加した場合はそれ以下)でした。ただし、この挿入ステップの前に削除ステップがありました(ステップ1でnをヒットできなかったため)。この削除手順で削除した最後の値qは、アルゴリズムの動作方法により、必然的にpよりも小さくなりました。しかし、我々は削除する前に手段があることのqを、私たちが持っていたn型のp + qは以下)未満であります N。しかし、それは矛盾です。なぜなら、別のqを削除する代わりにn-p + qを打ったときに整数の削除を停止しなければならなかったからです。これは上記のポイント(2)を証明します。これで、常に削除ステップで終了するため、すべての非三角形の数値に偶数の出力があることがわかりました。

次に、各挿入ステップで1つの値しか挿入できないことを証明します(3)。これは本質的に(2)の結果です。私たちは一つの値を追加した後、我々はヒットしないことが示されたN正確かつ不平等を使用していたことを証明するため、我々はまた、下に終わることができませんnはそれ以来(N-P + qがまだ未満となり、Nと我々は削除してはいけませんそもそも多くの値)。したがって、1つの値を追加するたびに、小さい値を削除してnを下回ったため、nを超えることが保証されます。したがって、合計の上限が1つおきに1ずつ増加することがわかります。この上限の初期値を知っています(最小のmです。T m> n)。最後の合計に達したら、この上限を把握する必要があります。その場合、ステップ数は単に差の2倍(プラス1)です。

これを行うには、(4)、最終合計が常にnをできるだけ多くの整数に分解すること、またはその分解の最大値が最小になる分解(つまり、可能な限り早い分解)であることを証明します。矛盾によってこれを繰り返します(この部分の表現はもう少し厳密かもしれませんが、私はすでにこれに時間をかけすぎています...)。

早い/最長の可能な分解言うnがあるいくつかの+(+ 1)+ ...(B-1)+ B≤B 、およびアルゴリズムは、それをスキップ言います。つまり、bが追加された時点で、aは合計の一部になってなりません。場合は和の一部だったは、我々が持っていると思いN≤よその瞬間。したがって、合計にはaからbまでの値のみが含まれ、nに等しいため停止します(したがって、この分解をスキップしなかった)か、合計でaより小さい値が少なくとも1つあり、nがsの場合に勝ちますそして、その値は正確な合計に達するまで削除されます(再び、分解はスキップされませんでした)。したがって、bを追加する前にaを削除する必要があります。しかし、これは、aが合計の最小成分であり、最大値がまだbでない状況に到達する必要があることを意味します。しかし、その時点で我々は削除することはできません合計がはっきり未満であるので、n個(以降Bが不足している)、私たちが追加されるまで最初の値を追加する必要がしているので、Bをとヒットnは正確に。これは証明します(4)。

したがって、これらのことをまとめると、最初のステップのペアではA002024(n)の最大値が得られることがわかります。最終的な分解の最大値はA212652(n)であることがわかります。そして、この最大値はステップのペアごとに1回増加することがわかっています。したがって、最終的な式は2 *(A212652(n)-A002024(n)+ 1)です。この式は、2の代わりに1ステップだけが必要な場合を除いて、三角形の数に対してほとんど機能します。そのため、三角形の数のインジケーター関数(またはその逆のほうが便利な方)で結果を修正します。

最後に、実装については。前者のシーケンスでは、OEIS の式MIN(odd d | n; n / d +(d-1)/ 2)を使用しています。この式に2の係数を入れてMIN(odd d | n; 2n / d + d-1)を取得すると、数バイトを節約することがわかります。なぜなら、その-1は最初のバージョンで+1でキャンセルされるためですF(n)を直接三角および非三角数のための2つのケースをコードします。コードでは、これは次のとおりです。

Min[2#/(d=Divisors@#~Cases~_?OddQ)+d]

後者のシーケンス(1, 2, 2, 3, 3, 3, ...)には、単純な閉じた形式を使用できます。

⌊(2#)^.5+.5⌋

そして最後に、8n + 1が完全な正方形であるときは常に、三角形の数の逆指標関数は0です。これはMathematicaで次のように表現できます。

⌈Sqrt[8#+1]~Mod~1⌉

これらの最後の2つのシーケンスを表現し、それらの間で一定のオフセットをシフトする方法はたくさんありますので、これはまだ最適な実装ではないと確信していますが、これが他の人に新しいアプローチを検討するための出発点になることを願っています独自の言語。

私はこのすべての問題に取り組んだので、ここにn = 1000までのシーケンスのプロットを示します(数秒で100kを計算することもできますが、実際には追加の洞察は表示されません)。

enter image description here

これらの非常にまっすぐな線についてのバリエーションを調べるのは面白いかもしれませんが、私はそれを他の誰かに任せます...


私は最終的にあなたの答えを徹底的に読むのに時間をかけました。これは素晴らしいです。(3)は既にアルゴリズムで想定されていることに注意してください(ステップ#3はifであり、しばらくではありません)が、その証拠はもちろん、大歓迎です。
アーナルド

@Arnauldありがとうございます。:) if / whileの部分を見落としている/誤解しているに違いありません。良いこと、それは違いをもたらさない。
マーティンエンダー

7

Mathematica、72バイト

(For[l=u=c=k=0,k!=#,c++,If[#>k,While[#>k,k+=++u],While[#<k,k-=l++]]];c)&

整数の引数を取る純粋な関数。

使い方

For[ ... ]

Forループ。

l=u=c=k=0

初期化; セットl(下)、 u(上)、 c(カウンタ)、およびk0〜(合計)。

k!=#

調子; k入力と等しくない間、繰り返します。

c++

インクリメント; カウンタをインクリメントしますc

If[#>k,For[,#>k,,k+=++u],For[,#<k,,k-=l++]]

If[#>k, ... ]

入力が次より大きい場合k

While[#>k,k+=++u]

入力がより大きいながらk、増加u及び増加kによってu

入力が次より大きくない場合k

While[#<k,k-=l++]

入力が未満である間k、減少kl、増加しますl

( ... ;c)

cループの後に戻ります。


1
For[,...]ビートWhile[...]
マーティンエンダー


5

Haskell70 63 68 64バイト

編集:

  • -7バイト:の意味を否定することにより、スペース、2つの記号、およびいくつかの括弧を取り除きましたa。説明のオフバイワンエラーを修正しました。
  • 5バイト:なんてこった、完全に逃している65536の要件、およびそれがラップ(限り範囲を加算されますが、番号自体(2)に到達したとき、彼らは唯一のヒットを得るため、2の(1)の力は、特に高価で判明周りゼロ)常に。合計を数式に置き換えました。
  • -4バイト:調整ab直線的にキャンセルする加算式で用語を取得します。

1#1 整数を取得して返す匿名関数です。

として使用し(1#1) 100ます。

1#1
(a#b)n|s<-a*a-b*b=sum$[a#(b+2)$n|s>8*n]++[(b#a)(-n)+1|s<8*n]

オンラインでお試しください!

使い方

  • (a#b)n計算の現在のステップを表します。a, b数字がでている1, 3, 5, ..間、nステップに応じて正または負のいずれかになります。
    • ステップ1または3の場合、リスト[(a+1)/2,(a+3)/2..(b-1)/2]と目標番号を表します-nます。
    • ステップ2で、リスト[(b+1)/2,(b+3)/2..(a-1)/2]と目標番号を表しnます。
  • a, bとリストの間の奇妙な対応は、短い式で総和をすることができるためですs=a*a-b*b
    • ステップ1および3では、これはと同じs= -8*sum[(a+1)/2..(b-1)/2]です。
    • ステップ2では、これはと同じs=8*sum[(b+1)/2..(a-1)/2]です。
  • 分岐は、それぞれ1つのケースのみで要素を生成するリスト内包表記を使用し、結果を合計することによって行われます。
    • の場合s>8*nb再帰する前に2ずつ増加します。
      • ステップ1と3ではリストを拡大し、ステップ2ではリストを縮小します。
    • の場合s<8*n、再帰はとを交換してステップを変更ab、を否定nし、結果に1が追加されます。
    • の場合s==8*n、2つのリスト内包表記のどちらも要素を提供しないため、合計は0です。
  • (1#1) n開始前のダミーの「ステージ2」を表し、すぐにステップ1に変更され、リストを作成し[1..0]=[]ます。

4

PHP> = 7.0、74バイト

while($i=$r<=>$argn)for($s++;($r<=>$argn)==$i;)$r+=$i+1?-++$y:++$x;echo$s;

宇宙船オペレーターを使用する

オンラインでお試しください!

拡大

while($i=$r<=>$argn) # if input is not equal sum of array
  for($s++;  # raise count steps
  ($r<=>$argn)==$i;)
  # so long as value compare to input has not change to lower/higher to higher/lower or equal  
    $r+=$i+1
      ?-++$y # if $i was higher remove the first integer
      :++$x;} # if $i was lower add the next highest integer     
echo$s; # Output steps

なに$argn
-chx

@chx -Rオプションを使用
ヨルグヒュルスマン

ワオ。私は聞いたことがない-Rくらい小さいですargvargi。もちろんargcとargvを知っていました。非常に興味深い、ありがとう。
chx

4

C、94 91バイト

オンラインで試す

c;s;m;M;f(n){while(s-n){while(s<n)s+=++M;c++;if(s==n)break;while(s>n)s-=++m;c++;}return c;}

初期化されていない変数の広範な使用oO
YSC

Cの@YSC、初期化されていないグローバルに宣言された整数は、コンパイル時にゼロに設定されます。
続きを

これを忘れました。このリマインダーをありがとうございます。
YSC

参考までに、別のC回答を投稿しました。私が使用したトリックの少なくとも1つは、他のコンパイラーでは機能しませんが(欠落しているreturn)、機能するものについては、自由にそれらを回答に組み込んでください。
hvd

3

JavaScript(ES6)、82バイト

D=(o,a=0,b=1,d=1,c=0)=>a<o?D(o,a+=b,b+1,d,c+(a>=o)):a>o?D(o,a-=d,b,d+1,c+(a<=o)):c

テストスニペット


これを言ってすみませんが、各ↄは3バイトとしてカウントされます。簡単に名前を変更できるので、問題ではないと思います。
Ørjanヨハンセン

@ØrjanJohansen思い出させてくれてありがとう。コードを長さではなくバイトでスコアリングすることを忘れないでください。「簡単に名前を変更できる[変数]」に関するコミュニティのコンセンサスがあるとは思わないので、投稿を編集しました。しかたがない。
R.ガプス

3
スニペットは6553で「Too much recursion」で失敗します。6553はノード(6.9.1)でローカルに動作しますが、65536は動作しません(「最大呼び出しスタックサイズを超えました」)。
eush77

3

dc、61バイト

dsN[ddd9k4*d2*1+dv-0k2/-d1+*2/-d[q]s.0=.-lN-0lN-sNlFx]dsFxz2-

オンラインでお試しください!

説明

メインの再帰マクロ:

ddd9k4*d2*1+dv-0k2/-d1+*2/-d[q]s.0=.-lN-0lN-sNlFx
   9k4*d2*1+dv-0k2/-                              # Compute triangular root
                    d1+*2/                        # Compute triangular number
  d                       -d[q]s.0=.              # Check if sum is exact
 d                                  -lN-          # Compute S-N or S+N
                                        0lN-sN    # Update N := -N
d                                             lFx # Leave the trail and recurse

このマクロ:

  1. スタック上の現在の数を超える最小の三角形の数を見つけます(修正された三角根の式を使用)。
  2. 三角和Sが現在の数値を正確に表しているかどうかを確認します。存在する場合は終了します。
  3. いずれかでステップ1に進みます S+N(過近似)またはS-N(過小)の、選択は反復間で交互に行われます。

終了すると、スタックに残されたトレイルは、メインプログラムにそれが何回繰り返したかを伝えます。


3

Pythonの3、150の 138バイト

n=int(input())
S=sum
l=[1]
i=s=1
while S(l)<n:i+=1;l+=[i]
while S(l)!=n:
 while S(l)>n:l.pop(0)
 s+=1
 if S(l)<n:i+=1;l+=[i];s+=1
print(s)

変更ログ:

  • appendを+ =に変更し、その他を削除しました(musicman523、Loovjoに感謝、-12バイト)

1
ステップ#2は、リストから1つまたは複数の用語を一度に削除できます(N = 11の例では1、2、3など)が、いずれにしても1ステップとしてカウントされます。
アーナルド

@Arnauldはそれを見落としていました。一定。
-L3viathan

1
なぜelse必要なのか説明できますか?elseループは常に正常に終了するため(なしでbreak)、毎回実行されると信じており、ループなしでも正常に動作するようです。
-musicman523

A=l.append部品をスキップしてl+=[x]代わりに使用できます。
-Loovjo

3

バッチ、126バイト

@echo off
set/an=s=l=u=0
:l
if %s% lss %1 set/as+=u+=1,n+=!!l&goto l
if %s% gtr %1 set/as-=l+=1&goto l
cmd/cset/an+n+2-!l

説明:lステップ2が一度も実行されていない場合はゼロです。これによりn、ステップ3の反復回数を追跡できます。アルゴリズムはステップ3で停止しないため、ステップ1を1回、ステップ2 n+1を合計で実行する必要があります。n+n+2ます。ただし、パラメーターが三角形の場合、ステップ2は実行されないため、1ステップを減算する必要があります。



2

Mathematica、92バイト

(For[q=a=b=0;t={},t~AppendTo~q;q!=#,If[q<#,q+=++b,q-=++a]];Length@Split@Sign@Differences@t)&

整数の引数を取り、整数を返す純粋な関数。

変数abは、検討中の合計の(常に変化する)開始番号と終了番号をq表し、現在の合計(からa+1までの数b)を表します。これまでtq遭遇したすべての値を追跡します。これらの変数を初期化した後、Forループは実行を続け、入力に等しくなるIf[q<#,q+=++b,q-=++a]まで、末尾に新しい数値を追加するか、仕様で指定されているように先頭の数値を減算qします。

ここで、途中tで検出されたq値のリストからステップ数を抽出する必要があります。たとえば、入力がの11場合、Forループはtequalingで終了し{0,1,3,6,10,15,14,12,9,15,11}ます。これからステップ数を計算するために見つけた最良の方法は、差分が上昇から下降に切り替わる回数をカウントすることです。それが冗長コマンドのLength@Split@Sign@Differences@t機能ですが、改善できると思います。


2

C(tcc)、71バイト(61 + 10)

コマンドライン引数(スペースを含む):

-Dw=while

ソース:

c,m,M,s;f(n){w(++c,s-n){w(c&s<n)s+=++M;w(~c&s>n)s-=m++;}--c;}

使い方:

cステップ数をカウントします。mそしてM、範囲の最小値と最大値を格納しますs、合計。最初は、すべてゼロです。

継続的にc増加し、とs比較されnます。それらが等しくない限り:

  • cが奇数の場合s<n、範囲の最後に整数を追加Mします。1ずつ増加sMます。

  • cが偶数の場合s>n、範囲の先頭から整数を削除します:で減少smm1 で増加します。

ループが終了すると、 c 1つ多くなりすぎます。これをデクリメントすると正しい結果が生成され、戻り値として機能する正しいレジスタで計算されることがあります。

面白いことに、Khaled.KのCの回答とまったく同じ変数名を使用しています。それらはコピーされません。


1

Perl 6、114バイト

{((0,0,1),->(\a,\b,\c){b,(a..*).first(->\d{(d,b).minmax.sum*c>=$_*c}),-c}...->(\a,\b,\c){(a,b).minmax.sum==$_})-1}

(以前のHaskellに触発された実装に)

試してみてください
コンピューター上で45秒未満で65536の入力で実行されますが、TIO.runで60秒未満で実行することができませんでした。
Rakudo v2017.04 +があり、v2017.01があります。
Rakudo / NQP / MoarVMはほぼ毎日最適化を行うため、時間内に最適化するために必要な暫定的な数の最適化が可能です。


拡大

{
  (

    # generate a sequence

    (0,0,1),           # initial value 

    -> (\a,\b,\c) {
      b,               # swap the first two values

      (a..*)
      .first(          # find the first number that brings us to or past the input

        -> \d {
          (d,b).minmax # get a Range object regardless of which is larger
          .sum * c     # sum it, and negate it every other time

          >=           # is it equal to or greater than

          $_ * c       # negate the original input every other time
        }

      ),

      -c               # invert for next round
    }

    ...                # keep doing that until

    -> (\a,\b,\c) {
     (a,b).minmax.sum == $_ # it finally reaches the input
    }

  ) - 1 # count the number of elements in the sequence
        # and subtract one for the initializer
}

Rakudoには最適化があるRange.sumため、すべての値を反復処理する必要はありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.