問題概略
整数 を 2 のべき乗の和で表すことを考える。ただし各数は高々 2 回しか使ってはいけないものとする。この表し方の数を とする。 と定義する。
たとえば 10 には 5 通りの異なる表し方があるので である。
\begin{align*}
10=1+1+8=1+1+4+4=1+1+2+2+4=2+4+4=2+8
\end{align*}すべての正の有理数 に対して となる が少なくとも一つ存在することが示せる。
たとえば となる最小の は 241 であり,その 2 進法表示は である。
この 2 進数を上の位から順に読んでいくと「1 が 4 つ,0 が 3 つ,1 が 1 つ」となる。
4, 3, 1 を 241 の「短縮された 2 進法表示」と呼ぶ。となる最小の を短縮された 2 進法表示で求めよ。
解説の pdf も作りました。きれいなレイアウトで読みたい方はこちらをどうぞ。
カルキン・ウィルフ・ツリー
この は第 169 問でも出てきました。くわしいことはそちらの解説に譲りますが,次の式が成立します。
これを使うと の引数を減らせます。
なんとなく合同式を連想させる式ですが,実は木として図示すると 2019 年の大阪大学の入試でも出題されたカルキン・ウィルフ・ツリー(Calkin – Wilf tree)の矢印を逆向きにしたものになっています。
既約分数の分母と分子は互いに素なので,図 1 のように分母,分子の大きい方から小さい方を引く操作を繰り返せば最後は必ず になります。
その経路を逆向きにたどれば から にたどりつきます。ゴールの分子の引数が求める です。
これを実験で確かめてみましょう。 から までの経路は図 3 のようになります。
図 3 の経路を逆向きにたどるとき,分子の引数は次のように変化します。
- 「」のとき なので 2 進法では「1 ビット左にシフトして 1 を足す」
- 「」のとき なので 2 進法では「1 ビット左にシフト」
これらを単に「」「」であらわしたものが図 4 です。問題文に書いてある通り です。
手計算で解ける
に対する経路を描いたら手計算で解けてしまいました。
mathematica で解く
手計算で解けてしまいましたが,mathematica でも解くことにします。
これまでの議論からほとんどの移動において「移動回数は分母と分子の割り算の商」「移動した後の値は余り」が正しいことがわかっています。
ただ,分母か分子が1になった後は話しが違います。 からの経路と からの経路は次のようになります。
- 図 7 の経路を逆にたどるとき,1 に対して を 回行うので になる
- 図 8 の経路を逆にたどるとき,1 に対して を 回行うので になる
これをふまえたコードを書きました。up が分子で dw が分母です。
これらが 1 でない間は while ループでまとめて処理して,1 になったら個別に処理しています。計算時間は一瞬でした。
In[]:= AbsoluteTiming[ solve[p_, q_] := Module[{res = {}, up, dw}, {up, dw} = {p, q}/GCD[p, q]; While[up != 1 && dw != 1, If[up > dw, AppendTo[res, Quotient[up, dw]]; up = Mod[up, dw], AppendTo[res, Quotient[dw, up]]; dw = Mod[dw, up]]]; If[up == 1, AppendTo[res, dw]; Return@Reverse@res]; If[dw == 1, AppendTo[res, {up - 1, 1}]; Return@Reverse@Flatten@res]]; ans = solve[123456789, 987654321];] Out[]= {0.0000738, None}