日本語翻訳サイトは、プロジェクトオイラー日本語 でネット検索です。
問80「平方根の10進展開」
よく知られているように、自然数の平方根が整数ではないならば、それは無理数である。
そのような平方根の10進展開(decimal expansion)は繰り返しを持たない無限小数になる。
2の平方根は1.41421356237309504880..., であり、その頭から100桁の数字を合計すると475になる。
初めの100個の自然数の平方根のうち、無理数について、それぞれの頭から100桁の数字を足した数の総和を求めよ。
注意!!!
自力で解きたい人へ
以降の記述には解法に関するネタバレが含まれます。
私の回答例は以下の通りです。
def f(n, m): L, c = [i*i for i in xrange(n+1)], 0 for i in xrange(n+1): if i in L: continue M, s, t = [], 0, i for j in xrange(m): N = [s*10+k for k in xrange(10)] for k in range(10)[::-1]: w = s*10+k if w*k<=t: break M.append(k) s, t = w+k, (t-w*k)*100 c += sum(M) return c n, m = 100, 100 print f(n, m)
平方根を開平法で求めます。
(参考)
・開平法(wikipedia)
・ルートを開こう(中村文則氏のサイト)
1.関数f(n, m)
・n個の自然数の平方根のうち、無理数について、それぞれの頭からm桁分の数字の和の総和を返します。
・リストLは自然数の2乗のリストで、その要素は平方根が有理数になる自然数す。
・変数cに求める総和を累積していきます。初期値は0です。
・ループ変数iが平方根を求める対象の自然数です。
iがリストLに含まれている場合は対象外なので処理を飛ばします。
・リストMは平方根の各桁ごとの数字をためていくリストです。
・sは初期値0です。
・端数tは、元の数から、平方根を求めた桁までの2乗を差し引いた端数です。
最初は平方根は1桁も求まっていないので、tの初期値はiです。
・ループ変数jは平方根の左端の桁位置を0とした桁位置を示します。
・for k in range(10)[::-1]:
w = s*10+k
if w*k<=t: break
ループ変数kは、0から9までの配列を逆順に1つずつ取り出します。
1つ前のループで計算したsの桁を1つ上げて(10倍して)kをたした値をwとし、
wとkの積がtを超えない最大値となるkを探します。
このkが平方根の求める桁の値です。
・s, t = w+k, (t-w*k)*100
上記のkで1桁進みましたので次の桁の準備をします。
wとkの和をsとします。
新たに決定した桁の分である、wとkの積を端数tから差し引きます。
100の平方根が10なので、平方根は元の数2桁ごとに1桁決まります。
このため端数tは100倍しておきます。
解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
40886
0 件のコメント:
コメントを投稿