2013年8月25日日曜日

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

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

問81「経路の和:2方向」

下記の5次の正方行列で, 左上のセルから開始し右下のセルで終わるパスを探索する. 
ただし下方向と右方向にのみ移動できるものとする. 
通過したセルの和が最小となるパスは赤の太字で示されたもので, その値は2427である.

131 673 234 103 18 
201 96 342 965 150 
630 803 746 422 111 
537 699 497 121 956 
805 732 524 37 331 

今, 31Kのテキストファイルmatrix.txt (右クリックして, 『名前をつけてリンク先を保存』)には80×80の行列が書かれている. 
同様に左上のセルから開始し右下のセルで終わり, かつ右方向と下方向にのみ移動するときの最小のパスの和を求めよ.



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






私の回答例は以下の通りです。

def f(fn): import sys, copy L0 = open(fn).read().split("\n") L1 = [s.split(",") for s in L0 if s] tn, yn = len(L1), len(L1[0]) L2 = [[int(t) for t in s]+[sys.maxint] for s in L1]+[[sys.maxint]*yn] L3 = copy.deepcopy(L2) L4 = [["" for i in xrange(yn)] for j in xrange(tn)] for i in range(tn)[::-1]: for j in range(yn)[::-1]: if i==tn-1 and j==yn-1: continue elif L3[i][j+1]<L3[i+1][j]: L4[i][j]="R" elif L3[i+1][j]<=L3[i][j+1]: L4[i][j]="D" L3[i][j] += {"R":L3[i][j+1], "D":L3[i+1][j]}[L4[i][j]] i,j,L5,L6 = 0,0,[],[] while L4[i][j]: L5.append(L2[i][j]) L6.append(L4[i][j]) if L4[i][j]=="D": i += 1 else: j += 1 L5.append(L2[i][j]) return L3[0][0], L5, L6 import os fn = os.path.join(os.path.dirname(__file__),"problem081_matrix.txt") s, val, dir = f(fn) print "sum:", s print "val:", val print "dir:", dir



問18問67を参考にしました。

1.関数f(fn)
・下方向と右方向にのみ移動して通過したセルの最小和、そのパスを返します。

・リストL0にmatrixファイルの全データを行ごとに格納します。

・リストL1としてL0を行ごと値ごとの2次元配列にします。
 ここで縦横の要素数をそれぞれtn, ynとします。

・リストL2としてL1を数値化し、各列の最右端と最下段の要素を他の要素と同様に判定できるようにするために、各列の最右端と最下段に最大数値maxintを付加します。

・リストL3の初期値としてリストL2の値をコピーします。
 L3=L2とすると参照情報(ポインター)がコピーされ、値のコピーになりません。
 一次元配列のコピーは、L3=L2[:]ですが、
 二次元配列のコピーは、L3=L2[:][:]としてもうまくいきません。
 import copyしてから、copy.deepcopy()を使います。

・i,jの二重ループの中で右下から左上に向けて遡るように順にたどり、
 各値から終点に向けて進んだときの最小累積値をリストL3に設定します。
 また最小累積値となる次の値の方向を右方向R、下方向DをリストL4に設定します。

・始点から終点に向けて最小累積値になるように方向リストL4をたどっていき、
 リストL5にそれぞれの道筋の値を、リストL6に方向の値を設定していきます。
 

解答はこのすぐ下の行です。文字の色を白にしてます。選択状態にすると見えます。
sum: 427337
val: [4445, 2697, 5115, 718, 2209, 2212, 654, 1443, 5741, 1585, 6935, 4497, 955, 101, 1478, 2509, 5436, 1732, 9480, 706, 496, 101, 5913, 93, 1899, 328, 2876, 3604, 673, 158, 5093, 2447, 5782, 3967, 1716, 931, 239, 2000, 1228, 3513, 1909, 354, 2410, 4171, 2709, 341, 5866, 106, 6379, 508, 811, 2871, 3525, 6356, 3906, 1212, 5812, 345, 16, 691, 2388, 1383, 1555, 1833, 739, 2100, 5800, 728, 4299, 10, 1929, 114, 6393, 9398, 265, 2622, 76, 2874, 880, 7270, 4071, 697, 9060, 3578, 1163, 1228, 2621, 3275, 2737, 7731, 486, 5726, 679, 355, 1330, 2933, 985, 3200, 1663, 1456, 6846, 3120, 1211, 1622, 3176, 4524, 3996, 615, 2863, 1715, 242, 958, 3058, 584, 3234, 9688, 1549, 2917, 394, 3081, 2581, 2994, 923, 2705, 4266, 3232, 2264, 6761, 363, 483, 556, 619, 3212, 3374, 3510, 1129, 3568, 2241, 2625, 2666, 4609, 1061, 2260, 3199, 1150, 1865, 1130, 3144, 163, 6310, 2854, 3503, 3391, 6932, 1040, 5128, 1113, 3406, 7981]
dir: ['R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', 'D', 'R', 'R', 'R', 'D', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'D', 'R', 'D', 'R', 'D', 'D', 'R', 'R', 'D', 'D', 'D', 'D', 'D', 'D', 'R', 'D', 'D', 'D', 'D', 'D', 'R', 'D', 'D', 'R', 'R', 'D', 'R', 'D', 'R', 'R', 'R', 'D', 'R', 'R', 'D', 'D', 'D', 'D', 'D', 'R', 'R', 'R', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'R', 'R', 'D', 'D', 'D', 'D', 'D', 'R', 'D', 'D', 'D', 'R', 'D', 'R', 'D', 'R', 'D', 'R', 'R', 'R', 'D', 'D', 'R', 'R', 'R', 'D', 'R', 'R', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'R', 'R', 'R', 'R', 'R', 'R', 'D', 'D', 'D', 'D', 'D', 'R', 'R', 'R', 'R', 'R', 'D', 'R', 'D', 'R', 'R', 'R', 'R', 'D', 'D', 'R', 'D', 'R', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'R']

2013年8月15日木曜日

プロジェクトオイラー 問80別解

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

問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 x, a = i*10**m, i*10**(m*2) while x*x-a>1: x = (x+a/x)/2 c += sum([int(s) for s in str(x)[:m]]) return c n, m = 100, 100 print f(n, m)


平方根をニュートン法で求めます。
ニュートン法は方程式の解を近似計算する数値計算法です。
ニュートン法ではf(x)=0となるxを求める際に、xの近傍のxnでの接線とそのX軸との交点xn+1を順に求めていくことを繰り返してxの近似値を求めます。

(参考)
ニュートン法(wikipedia)

y=f(x)において、x=xnでの接線の傾きは微分係数f'(xn)なので以下の式が成り立ちます。
f(xn) = f'(xn) × (xn - xn+1)
式変形して、
xn+1 = Xn - f(xn)/f'(x)

当問題では平方根を求める元の数をaとして
f(x) = x2 - a としてf(x)=0となるxの近似値を求めます。
なお、xもaもそのままの値では小数点以下の桁が丸められてしまうので10のm乗倍などして大きな整数値にしてから処理して、x2 - a が1を超える場合に近似値を求め続けていきます。

開平法と比べ、ループ変数iの内側が簡単な式になっています。
処理時間も私の作った開平法ロジックと比べて30%程度です。


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

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

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

問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

2013年7月31日水曜日

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

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


問79「パスコードの導出」
オンラインバンクで通常使われるsecurity methodは,パスコードからランダムに選んだ3文字をユーザーに要求するものである.
たとえば, パスコードが531278のとき,2番目, 3番目, 5番目の文字を要求されるかもしれない. このとき, 期待される答えは: 317 である.

テキストファイルkeylog.txtには, ログインに成功した50回の試行が記録されている.
3つの文字が常に順番通りに要求されるとするとき, ファイルを分析して, 
可能なパスコードのなかでもっとも短いものを見つけよ.



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






私の回答例は以下の通りです。
def f(fn):
	L0 = open(fn).read().split()
	L1 = [[[],[]] for i in xrange(10)]
	for s in L0:
		t = [int(i) for i in s]
		for i in xrange(len(t)):
			for j in xrange(len(t)):
				if i!=j: L1[t[i]][int(i<j)].append(t[j])
	L2 = [[sorted(set(t)) for t in s] for s in L1]
	L3 = [[len(s[i]) for i in [0, 1]]+[j] for j, s in enumerate(L2)]
	L4 = sorted([s for s in L3 if s[0]+s[1]])
	L5 = [str(s[-1]) for s in L4]
	return "".join(L5)

if __name__=="__main__":
	import os
	fn = os.path.join(os.path.dirname(__file__), "problem079_keylog.txt")
	print f(fn)



1.関数f(fn)
・キーログファイルfnを分析して、最小文字列長のパスコードを返します。

・リストL0は、キーログファイルの全データを格納した配列リストです。

・リストL1は、各数字の左右にくる数字のリストを要素に持つリストです。
 [数字iの左にくる数字、数字iの右にくる数字]というリストをi番目の要素に持ちます。

・リストL2は、上記リストL1の二重配列の値をユニーク化して昇順に並べます。
 set関数で集合型にすることでユニーク化し、sorted関数でソートします。
 pythonの集合型は、ハッシュ値を持ち、値変更不可、重複値を持てない配列です。

・リストL3は、左右にくるユニーク値の個数のリストを要素に持つリストです。
 [数字iの右にくるユニーク値の個数、数字iの左にくるユニーク値の個数]というリストをi番目の要素に持ちます。

・リストL4は、上記リストL3から未使用数字を除去し、各数字の左にくるユニーク値の個数が少ない順に並べたリストです。
 具体的には左右のユニーク値の個数の和が正(論理的にTrue)の要素だけをリストL3から取り出して設定します。

・リストL5は、上記のリストL4の末尾要素に該当数字が格納されているので、それを文字型にしたリストです。

・ここまで処理して上記リストL5の要素を、連結文字なしで順に連結して返します。

2.関数の外
・fn = os.path.join(os.path.dirname(__file__), "problem079_keylog.txt")
 「__file__」はこのソースコードがあるプログラムファイルそのもののフルパスです。
 os.path.dirnameでこのフォルダを取得し、ファイルパスの区切り文字を挟みながら、キーログファイル名と結合します。

・print f(fn)
 関数fの戻り値を表示します。


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

2013年6月9日日曜日

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

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

問78「コインを山に分ける方法の数を調べ上げよ」
n 枚のコインを異なった方法で山に分ける場合の数を p(n) と表わす.
例えば, 5枚のコインを山に分ける異なったやり方は7通りなので p(5)=7 となる.

OOOOO

OOOO   O

OOO   OO

OOO   O   O

OO   OO   O

OO   O   O   O

O   O   O   O   O

p(n) が100万で割り切れる場合に最小となる n を求めよ.

-----


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






私の回答例は以下の通りです。
def f(n):
	L = [1]
	for j in xrange(1, n+1):
		r = 0
		for i in xrange(1, n+1):
			k = (i+1)//2 * ((i%2)*2-1)
			m = j - k*(k*3-1)//2
			if m<0: break
			r += ((i+1)%4//2*2-1) * L[m]
		if not r%n: return j, r
		L.append(r)
	return None
	
n=1000000
print f(n)



問76から3問連続で分割数の問題です。
それぞれ前の問を解決したロジックのままでは1分ルールに間に合いません。
ずいぶん考えたのですが、結果としてゼロから解法構築はできず、
ネット検索したロジックを実装しました。

wikipediaの「分割数」によれば以下のとおりです。
分割数の関数をpとして、
p(k) = p(k-1) + p(k-2) - p(k-5) - p(k-7) + p(k-12) + p(k-15) - p(k-22) - ...
p(0) = 1, 負の整数kに対してp(k)=0

関数pの引数の中で使用する値1, 2, 5, 7, 12, 15, ...は、
n=1, -1, 2, -2, 3, -3, 4, -4, ...に対する五角数n(3n-1)/2です。
また、p(k)を構成する各項の符号は、順に+, +, -, - の繰り返しです。

1.関数p(n)
・nで割り切れる最小の分割数を持つ整数とその分割数を返します。
・リストLは分割数の配列です。0以上の整数iの分割数をi番目の要素として持ちます。
・分割数リストLの初期値は、0の分割数で、定義により、1をセットします。
・ループ変数jごとに変数rに上記の各項の和rをためます。このrが整数jの分割数です。
・ループ変数iが分割数の式の各項に対応します。
 整数kの分割数は、k未満の分割数から計算できるので、
 ループ変数iは1からnまでの範囲内で負の数の分割数が必要になったところまでです。

ループ変数i
 1, 2, 3, 4, 5, 6, 7, 8, ... (A)

(i+1)//2
 1, 1, 2, 2, 3, 3, 4, 4, ... (B)

(i%2)*2 -1
 1,-1, 1,-1, 1,-1, 1,-1, ... (C)

よって、五角数を求めるための整数kは、(B)と(C)の積で、
k
 1,-1, 2,-2, 3,-3, 4,-4, ... (D)

そして上記(D)に対応する五角数は、
k*(3*k-1)//2
 1, 2, 5, 7,12,15,22,26, ... (E)

nから上記(E)の五角数を引いた値をmとして、mの分割数を求めます。
ループ変数j未満の分割数はすでに分割数リストLにあります。

求める分割数を構成する各項の和を求める際の、各項の符号は以下の通りです。
(i+1)%4//2*2-1
 1, 1,-1,-1, 1, 1,-1,-1, ... (F)

・分割数rがnで割り切れるか判定します。
  r%nでrをnで割った余りを求め、割り切れると余り0で論理的にFalseになります。
  このFalseになったときが割り切れたときで、整数jとその分割数rを返します。


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

2013年5月26日日曜日

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

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

問77 「素数の和としての表し方が5000通り以上になる最初の数」
10は素数の和として5通りに表すことができる:

7 + 3
5 + 5
5 + 3 + 2
3 + 3 + 2 + 2
2 + 2 + 2 + 2 + 2

素数の和としての表し方が5000通り以上になる最初の数を求めよ.

-----


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






私の回答例は以下の通りです。
def p(n):
	L = [0,0]+[1]*(n-1)
	for i in xrange(n):
		if i*i>n: break
		if not L[i]: continue
		for j in xrange(i+i, n+1, i): L[j] = 0
	return [i for i in xrange(n+1) if L[i]]

def f(n):
	c = max(100, n)
	P = p(c)
	L = [1]+[0]*c
	for i in xrange(1, c):
		if i in P:
			for j in xrange(i, c+1):
				L[j] += L[j-i]
			if L[i]-1>=n: break
		else:
			if L[i]>=n: break
	return i

n = 5000
print f(n)


問76と同様の分割数を、この問題では素数で構成します。

1.関数p(n)
・n以下の素数リストを返します。
問37を流用しました。

2.関数f(n)
・素数の和としての表し方がn通り以上になる最初の数を返します。

・返却する値の最大値を超える分だけリストを用意し、
 自然数nを素数の和で構成するパターン数をリストLに格納します。
 このリスト要素の上限数をcとして仮決めし、forループを使用しています。

・リスト要素の上限数cは100とnの大きい方の値にしています。
 理由はnが大きくなるほどmは急激に増加しm<nとなりますが、
 問題文の例のようにmが小さい場合はn<mです。
 そしてn=100のパターン数が100通り以上あるのは明らかなので、固定で100としました。
 (実際にm<nとなるのは、n>19でした)

・ループ変数iは返却値の候補です。
 素数リストに存在する値かどうかで処理が分かれます。

・iが素数の場合、パターン数リストLのi以上c以下の全要素について、自分の要素番号よりもiだけ少ない要素番号に格納されている値を足していきます。
 これによってi個手前の要素にカウントされている件数に数えられているパターンに、+iを付加した新パターンの件数を累積することになります。
 またiが素数の場合、素数だけの場合も+iしてカウントすべきパターンになるため、カウント対象外の素数だけの場合も含んでいます。
 このため、パターン数がn通り以上かの判定には、パターン数リストL[i]に格納しているパターン数から-1した値を使います。

・iが素数でない場合、パターン数リストL[i]に格納しているパターン数で判定します。

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

2013年4月29日月曜日

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


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

問76 「2つ以上の正整数の和としての100の表し方は何通りか」
5は数の和として6通りに書くことができる:

4 + 1
3 + 2
3 + 1 + 1
2 + 2 + 1
2 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1

2つ以上の正整数の和としての100の表し方は何通りか.

-----


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






def g(n, m, d):
	if (n,m) in d: r = d[(n,m)]
	elif n<m or n<1 or m<1: r = 0
	elif n==m: r = 1
	else:
		d[(n-1,m-1)] = g(n-1, m-1, d)
		d[(n-m, m)] = g(n-m, m, d)
		r = d[(n-1,m-1)]+d[(n-m, m)]
	return r
	
def f(n):
	d = {}
	return sum([g(n,m,d) for m in xrange(2, n+1)])
	
n = 100
print f(n)


自然数nを異なるm個の自然数の和で表示するパターン数p(n, m)を求め、
mを2分割からn分割まで足せばいいと考えました。
問題文中のn=5の場合のパターンをよく見ると
「末尾が+1」のパターンは、5より1つ小さいn=4の場合のパターンに+1しただけで、パターン数としてはn=4の場合と全く同じです。
あとは、「末尾に+1が来ないパターン」ですが、この規則性がなかなかわからず長考に入ってしまいました。

どうしてもやり方がわからず、ネット検索したところ、
以下のことがわかりましたので参考にしました。

・自然数nを異なるm個の自然数の和に分割するパターン数は「分割数」と呼ばれている。
・自然数nnを異なるm個の自然数の和に分割するパターン数は以下の再帰的な記述ができる。
p(n, m) = p(n-1, m-1)+ p(n-m, m)...(1)

(1)式の「p(n-1, m-1)」部分は、
構成する項を値の大きい順に並べたときに末尾が1のパターン数です。
これは私も気づいていた、nより1つ小さい自然数を、mより1つ小さい個数に分けた場合のパターン数です。
最後の末尾に+1の項を付加することで、自然数nをm個に分割したパターンになります。

次の「p(n-m, m)」の部分ですが、これは
構成する項を値の大きい順に並べたときに末尾が1以外のパターンです。
m個の項すべてが1より大きいパターンなので、m個の項すべてから1ずつ引いてみると、
自然数(n-m)がm個に分割されている状態とまったく同じです。

(1)式のように分割する自然数や分割個数を小さくした再帰呼び出しで数量が確定します。

1.関数g(n, m, d)
・自然数nをm個の自然数の和に分割するパターン数を返します。
・dはキー(n,m)に対応するパターン数を格納する辞書(連想配列)です。
 一度計算した(n,m)のパターン数は辞書に格納して繰り返し参照することで速度向上を目指します。
・elif n<m or n<1 or m<1: r = 0
 elif n==m: r = 1
 再帰呼び出しの終了条件です。
 n<mの場合、自然数nよりも多くの部分には分けられないので、そのようなパターンは0件です。
 n,mいずれも1未満では分けられないので、そのようなパターンは0件です。
 n=mの場合、自然数nを同数の部分に分けるので全項目1+1+...+1にするパターン1つだけです。

2.関数f(n)
自然数nを異なるm個の自然数の和で表示するパターン数を関数g(n, m)を求め、
mを2分割からn分割まで足します。


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