2014年11月24日月曜日

プロジェクトオイラー 問97

プロジェクトオイラーの問題をpythonでやってみます。
日本語翻訳サイトは、プロジェクトオイラー日本語 でネット検索です。

問97「大きな非メルセンヌ素数」
100万桁を超える初めての素数は1999年に発見された. これはメルセンヌ素数であり, 26972593-1 である. 実際, 2,098,960桁ある. 
それ以降も, より多くの桁になるメルセンヌ素数 (2p-1の形の数) が他にも発見されている.

しかし, 2004年に, 非常に大きな非メルセンヌ素数が発見された. 
これは2,357,207桁の数であり, 28433×27830457+1である.

この素数の末尾10桁を答えよ.






注意!!!
自力で解きたい人へ
以降の記述には解法に関するネタバレが含まれます。






私の回答例は以下の通りです。
def f(a, n, p, b, m):
	k, t, c = n, 10**m, 1
	for s in str(p)[::-1]:
		c *= k**(int(s))%t
		k = k**10%t
	return (a*c+b)%t

def f2(a, p, b, m): return ((a<<p)+b)%(10**m)

#(a×(nのp乗)+b)の末尾m桁を返す
a, n, p ,b ,m =28433, 2, 7830457, 1,10
s = f(a, n, p ,b ,m)
print s

#(a×(2のp乗)+b)の末尾m桁を返す
a, p ,b ,m =28433, 7830457, 1,10
s = f2(a, p ,b ,m)
print s


1.関数f(a, n, p, b, m)
・a×np+b の末尾m桁を返します。

・for s in str(p)[::-1]:
 数値pをstr関数で文字型にして、文字のスライス機能の[開始:終了:刻み]での刻みを-1にすることで右から1文字ずつ、つまり1の位の数字から順に1つずつ取り出し、ループ変数sに設定します。

・c *= k**(int(s))%t
 k = k**10%t
 変数kは、ループ変数sの桁位置に相当するnの累乗値を設定します。
 初期値はnで、ループが回るにつれ、nの10回累乗、100回累乗、...と直前の累乗値を10回ずつ累乗していきます。
 変数cに、kのs乗をかけて、ためていきます。
 例えば、
 2の345乗ならば、(2の5乗) x ((2の10乗))の4乗) x ((2の100乗)の3乗)です。
 このときの「2の10乗」「2の100乗」が変数kで、各桁の数字が変数sです。

2.(別解)関数f2(a, p ,b ,m)
・a×2p+b の末尾m桁を返します。
 関数の中の累乗計算を、2の累乗に固定します。

・a<<p
 数値aをpビット左にシフトすることで、2進数でp桁繰り上がります。
 これは、数値aに対して2をp回かけることと同じです。

解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
8739992577

0 件のコメント:

コメントを投稿