競技プログラミングのためのF#入門
1 2 |
|
よく出てくる定型処理です. 暗記してもいいほどです. 自分用のライブラリを作って記録しておくといいでしょう. 私はArithmetics.fsxに記録しています.
今回入力のN
は1
以上の自然数です. しかしN=0
で問題(?)がある実装を紹介するため, 念のため場合分けを明確につけておきます.
結論からいうと再帰関数で0,1
の数値からなるリストとして二進展開を作ります. 最初に書いたようにN=0
の場合を別にして次のように書きます.
1 |
|
これで[1;1;0;1]
のようなリスト(int list
)ができます. ここから二進展開の文字列を作って文字列を零埋めします. 零埋めのよい方法がいまだによくわかっていないものの, C#の文字列系のメソッドを使えばいいでしょう. リストを文字列に変換して文字列を零埋めします.
1 |
|
frec [] N
以降は次のように処理しています.
List.map string
でint list
をstring list
に変換する.System.String.concat ""
でstring list
を空文字列で連結する.s.PadLeft
で文字列に対して零埋めする.いきなり二進展開で考えるとわかりにくいでしょう. K=10
として十進数を十進展開し, 最後にK=2
で置き換えると多少なりともわかりやすいはずです.
まず十進展開されたもとの数をN
とします. 特にN = 123456789
として, これの一番下からK
進展開を考えます. 一番下の桁は9
だから何とかしてN
から9
を切り出します. これをN
をK = 10
で割ったあまりとみなせばN%K
で9
が取れます. 次にN/K
を考えると一番下の桁が削れてN1 = 12345678
が得られます. これに対してさらにN1%K
を考えると8
が得られます. これを再帰的に続けてNk = 0
になるまで続ければ求める十進展開が得られます.
箇条書きでは次のように書けます.
K
進展開したい数をN
とする.N%K
で最低桁が得られるからこの値を積む.N1 = N/K
を次のステップに回す.N1%K
でN1
の最低桁, N
の二桁目が得られるからこの値を積む.N2 = N1/K
を次のステップに回す.Nk = 0
までくり返す.結論だけ書きます.
1 |
|
unfold
¶F#入門コンテンツでループは再帰の構文糖衣とみなせると書きました. 特にループは配列から配列を作るか, 配列から値を作るか二通りあると書きました. 今回の処理は再帰を使って値から配列(リスト)を生成しています. 特定の場合にはこの逆の処理をしてくれる関数があり, それはunfold
です. 慣れないと難しいため無理に使う必要はありません. しかし関数型言語による処理では時々顔を見せる関数であるため, 念のため紹介します.
本質的には再帰と同じで, 関数についてはリファレンスを見てもらうとして簡潔に結果だけ示します.
1 2 3 4 |
|
unfold
を使う場合は再帰と違ってArray.rev
で順序を反転する必要があります.