Problem 40

Problem 40
Problem 40(原文)

正の整数を順に連結して得られる以下の10進の無理数を考える:

0.123456789101112131415161718192021...
小数第12位は1である.

dnで小数第n位の数を表す.
d1 × d10 × d100 × d1000 × d10000 × d100000 × d1000000 を求めよ.


プログラムを書かなくても答えが求められそうな問題ですね。
中学入試とかにピッタリかもしれません。
もし紙とペンだけで解くのであれば、
1~9までを連結した数字は 0.123456789 で小数第 1 × 9 = 9 位まで、
さらに10〜99を連結した数字は 0.123...979899 で小数第 9 + 2 × 90 = 189 位まで、
さらに100〜999を連結した数字は 0.123...998999 で小数第 189 + 3 × 900 = 2889 位まで、

という感じで目的の d1, d10, d100, d1000, d10000, d100000, d1000000 を
全て求めてから積を取ることになるかと思います。
d1 = 1桁の最初の数の一の位
= 1
d10 = d(9 + 1)
= 2桁の最初の数の十の位
= 10の十の位
= 1
d100 = d(9 + 91) = d(9 + 2 * 45 + 1)
= 2桁の46番目の数の十の位
= 55の十の位
= 5
d1000 = d(189 + 811)
= d(189 + 3 * 270 + 1)
= 3桁の271番目の数の百の位
= 360の百の位
= 3
d10000 = d(2889 + 7111)
= d(2889 + 4 * 1777 + 3)
= 4桁の1778番目の数の十の位
= 2777の十の位
= 7
d100000 = d(38889 + 61111)
= d(38889 + 5 * 12222 + 1)
= 5桁の12223番目の数の一万の位
= 22222の一万の位
= 2
d1000000 = d(488889 + 511111)
= d(488889 + 6 * 85185 + 1)
= 6桁の85186番目の数の十万の位
= 185187の十万の位
= 1

で、答えは 1 * 1 * 5 * 3 * 7 * 2 * 1 = 210 ですね。
一応Pythonでコーディングしてみます。

s = ''
n = 1
while len(s) < 10 ** 6:
    s += str(n)
    n += 1

d = lambda n: int(s[n - 1])
print reduce(lambda a, b: a * b, [d(10 ** n) for n in xrange(1, 7)], 1)

# 検算用
assert d(1) == 1
assert d(10) == 1
assert d(100) == 5
assert d(1000) == 3
assert d(10000) == 7
assert d(100000) == 2
assert d(1000000) == 1


答えがあっていることが 0.563 [sec] でわかりました。
ちょっと計算時間かかりすぎな気がしますが、
とりえあず我慢しておきましょう。
面白い問題が見つかるまで粛々と解いていくのみです。