「今週のお題:文字数で数えるローマ数字」問題解答 ( CodeIQ )
はじめに
CodeIQという所で週次で出題される「今週のお題」シリーズに解答しましたので、ネタバレです。
問題
簡単に言うと、ローマ数字 ( 1~3999 ) の中で、指定した文字数で表現できる数は何個あるか。文字数が標準入力から与えられる時、個数を出力するプログラムを書く問題です。
解答
golf解
以下、golf解のRuby(77)
p (1..3999).map{|i|t=0;4.times{t+=i%5<4?i%5+i/5%2:2;i/=10};t}.count(eval *$<)
golf解と言っても特別なことはしていなくて、
1~3999と範囲は決まっているので、それぞれでの文字数を求め、countメソッドによって 入力値と文字数が一致する要素の数を数えます。 文字数については、10進表記での各桁 ( 4桁分 ) に対応する文字数の合計で求めます。 千の位も含め、どの桁でも文字数は同じ規則に従いますので、1個のループとして記述することができます。
( 以上、提出版のコメント )
の通りです。
その他の解
f=->n,d{0>(m=n<d*2?n:d*4-n)?0:m<1?1: d<2?m*2:(0..4).inject(0){|s,i|s+f[n-i,d-1]*(4>>(i-2).abs)}} n=eval *$< p (0..3).inject(0){|s,i|s+f[n-i,3]}
ローマ数字は10進3桁と、3以下しか表現できない1桁の計4桁ですが、これを任意の桁数に対応させたバージョンです。
最上位 ( この問題では千の桁 ) が i=0~3 に対して、それぞれ f(n-i,残り桁数) 通りという計算を行い、その総和を答えとします。f 自体は再帰で求めるようにしています。
各桁は0~4文字ですが、この文字数に対応する桁は、
- 0文字 … 0 の1通り
- 1文字 … 1,5 の2通り ( I,V や X,L等 )
- 2文字 … 2,4,6,9 の4通り ( II,IV,VI,IX や XX,XL,LX,XC等 )
- 3文字 … 3,7 の2通り ( III,VII や XXX,LXX等 )
- 4文字 … 8 の1通り ( VIII や LXXX等 )
です。なので、
という漸化式が成立します。
終わりに
まああんまり変なことはしていないので、あっさりと。