Digit Sumシーケンスの要素を効率的に見つける方法は?


20

興味をそそるだけで、プロジェクトオイラーの「最近の」カテゴリ(数字の合計シーケンス)から問題を解決しようとしました 。しかし、問題を効率的に解決する方法を考えることはできません。問題は次のとおりです(元の質問シーケンスでは最初に2つありますが、シーケンスは変更されません)。

Digit Sumシーケンスは、1,2,4,8,16,23,28,38,49 ....です。ここで、シーケンスのnth項は、シーケンス内でその前にある数字の合計です。シーケンスの1015th項を見つけます。

素朴なソリューションは多くの時間がかかるため実装できません。私はこの問題を行列の累乗の場合(時間がかかる)に減らすことを試みましたが、このシーケンスの繰り返しはかなり線形であるため、このような繰り返しを見つけることはできませんでした独特の。シーケンスは繰り返しによって管理されていることがわかります。O(log(1015))

an=an1+d(an1).....(1)

ここでanはシーケンスのnth項であり、dは入力として自然数が与えられると、その数字の桁の合計を返す関数です(例:d(786)=21)。2番目のアプローチは、シーケンス内のパターンを見つけることでした。シーケンスの最初のいくつかの用語は、次のように記述できることがわかります。

   a_1 = 1  
   a_2 = 1 + d( 1 )
   a_3 = 1 + d( 1 ) + d( 1 + d( 1 ) )
   a_4 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) )
   a_5 = 1 + d( 1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) + d( 1 +  d(  
   1 ) + d( 1 + d( 1 ) ) + d( 1 + d( 1 ) + d( 1 + d( 1 ) ) ) )

上記のパターンから、シーケンスのnth項は次の方法で生成できるようになります。

  1. 2n1 1の間に追加記号を入れて書き込みます。
  2. 最初の残して から、次の2 0項に関数dを適用し、次の2 1項に、次に次の2 2項に、というように関数dを適用します。1d202122
  3. 次に、適用された各関数の引数に上記のメソッドを再帰的に適用します。d

たとえば、n = 3の場合、次の操作を実行します。

    1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
    1 + d( 1 ) + d( 1 + 1 ) + d( 1 + 1 + 1 + 1 )
    1 + d( 1 ) + d( 1 + d(1) ) + d( 1 + d( 1 ) + d( 1 +d( 1 ) ) )

動的プログラミングによってIが生成することができの時間で、上記の方法使って用語をO LはO 、G 2 10 15、再びない良好ナイーブ溶液よりなります。nthO(log(21015))

EDIT 1
観察できるもう1つのことは、です。たとえば、d a 6= d 23 = d 32 = 5です。しかし、私はこの点を利用できません。再度、線形回帰関係(行列の累乗法)を見つけようとしましたが、見つけることができません。d(an)=d(2n1)d(a6)=d(23)=d(32)=5

編集2

以下は、より狭い範囲でシーケンスをプロットしたときのグラフです(シーケンスの最初の項がプロットされます)。 106ここに画像の説明を入力してください

PS:Project Eulerにソリューションを依頼することはお勧めできません。しかし、私は過去数日間円を描いて移動してきたので、新しい方向性やヒントが欲しいだけです。それも受け入れられない場合は、提案があれば質問を削除できます。


1
You are given a106 = 31054319.オリジナルのオイラー問題にヒントがあるように感じます。
フィリップハグランド

@FilipHaglundそれはヒントではありません。総当たり攻撃だけで、その値を簡単に計算できます。それはあなたのアプローチをチェックするためだけです。
サシャ


@EvilJSは、グラフをプロットして、ジグザグに徐々に増加するようにプロットできました。あなたは、「パターンをキャッシュ.. "」あなたの最後の点を精巧でした。
sashas

興味深いパターンがmod 9に見えることを考えると、シーケンスmod 11またはmod 99を見ると、何か面白いことが起こりますか?値mod 11は、奇数インデックスの数字の合計と偶数インデックスの数字の合計から導出できます。値mod 99は、隣接する桁のペアの合計から導出できます。
DW

回答:


4

(1,2,4,8,7,5)nth


nth

最初に速度を確保するためにいくつかの手順を実行することは、数値を配列に入れて、単純なmodおよびdivの計算を回避するのに適しています。これにより、一定のスピードアップが得られますが、重要な場合を見ることができます。

開始点から次の1つを計算し、次の1つを計算することができます。この点は桁数の変化です。
さらに重要なことは、パターンが数字の増加とともに変化していることです。
数字自体と比較して数字の合計は小さいため、ほとんどの操作で数字の一部のみが変更されます。
それでは、実際に何をキャッシュできますか?

同じ数字の合計を持つ2つの数字では、次の数字を取得するための加算が同じになることがわかっています。次はどうですか?

サーシャ

ネタバレ警告、以下は非常に明示的なキャッシュパターンです

それは変わらない数字のように、追加的な条件に依存し、実行、私はそれが呼び出すシフトとして量を開始、スタート

10009100nth

100
1001

10



1,2,4,8

11012183054065176077198059041003



100,1000,10000,100000,1000000...
100


4

あなたは「新しい方向またはヒント」を要求し、答えがわからないので、これをここに残します。それが役に立てば幸いです。いくつかのアイデア:

パターンmod 9があるのは理にかなっています。

k>1,kZ10k1mod9

これは帰納法で証明できます。

これは、すべての数値がmod 9の数字の合計と一致することを意味します。

an=d(an)mod9

an=an1+d(an1)=2d(an1)mod9

この繰り返しを拡大し続けると、

an=2nmod9

パターンmod 9について説明します。

an=9k+2n

一般的なコードよりも少ないコードを次に示します。

import matplotlib.pyplot as plt
import numpy as np

#sum digits of n
def sum_digits(n):
    s = 0
    while n:
        s += n % 10
        n //= 10
    return s

#get the sequence to n digits
def calculate(n):
    retval = [1]
    for i in range(n):
        retval.append(retval[-1] + sum_digits(retval[-1]))
    return retval;

#empirically confirm that a_n = 2^n mod 9
def confirmPow2(a):
    count = 0
    for i in a[:10000]:
        if((i%9) != (2**count % 9)):
            print "false"
        count = count + 1

#find gaps divisible by 9 in a subset of a
def find9Gaps(a):
    count = 0
    S = []
    for i in a[:10000]:
         S.append(((2**count ) - i)/9)
         count = count + 1
    return S

#repeatedly sum the digits until they're less than 9...
#gives some interesting patterns
def repeatedDigitSum():
    for i in range(1000, 1100):
         print "=========for ",i
         while i > 9:
                 i = sum_digits(i)
                 print i 


a = calculate(10**6)
b = find9Gaps(a)
plt.plot(range(len(b[:100])), b[:100])
plt.show()

プロット(最初の100件)は指数関数に見えますが、完璧だとは思いません。

ギャップのプロット

これが出力です

>>> plt.plot(range(len(b[5:60])), np.log2(np.array(b[5:60])))
>>> plt.show()

ギャップの対数プロット

私が最後に持っているのは、数字の数字を合計してから、結果の数字の数字を合計し、これを繰り返すと、最終的にその数字mod 9が得られるように見えることです。

10 mod 9のべき乗に関する上記の事実を考えると、意味があります。

nd(n)d(d(n))mod9

ただし、興味深い数字のシーケンスが得られます。

編集:どうやらこれは「デジタルルート」と呼ばれます。


1
少なくとも3回はコメントされました。また、指数関数的に見えるプロットを行う場合、対数を使用する必要があります。スケール軸でそれを通知しますか?読みやすい10 ^ 16語をプロットした場合、私は本当に感銘を受けます。

何回コメントされましたか?人々は「パターンmod 9」があると言っていましたが、それが何であるかが明確ではないと感じました。私はこれについて作業を続けることができるとは思わないので、自分が持っているものをいくつか調査してコメントしました。繰り返しますが、解決策はありませんが、質問は解決策を求めませんでした。
quietContest

numpyの休憩と私は本当にこの問題を追求し続けるための時間を持っていないので、EvilJS提案あたりの対数プロットを追加しました、任意の大きなをプロットすることはできません
quietContest
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.