第24回オフラインリアルタイムどう書く「多段階選抜」の rubyによる実装
問題 http://nabetani.sakura.ne.jp/hena/ord24eliseq/
解答リンク集 http://qiita.com/Nabetani/items/1c83005a854d2c6cbb69
イベント http://yhpg.doorkeeper.jp/events/13159
当日お見せした実装。
def is_sq(b)
(b**0.5).round**2==b
end
def is_cu(b)
(b**(1r/3)).round**3==b
end
module Enumerable
def prepend( a )
if block_given?
a.each{ |e| yield e }
self.each{ |e| yield e }
else
to_enum( :prepend, a )
end
end
end
def remove_before( seq )
seq.each_cons(2).select{ |i| ! yield i[1] }.map{ |i| i[0] }
end
def remove_after( seq )
seq.each_cons(2).select{ |i| ! yield i[0] }.map{ |i| i[1] }.prepend( seq.first(1) )
end
def solve_core( s )
seq=loop.lazy.with_index(1).map{ |*i| i.last }
s.chars.each do |cmd|
seq=case cmd
when "s"; remove_before( seq ){ |n| is_sq(n) }
when "S"; remove_after( seq ){ |n| is_sq(n) }
when "c"; remove_before( seq ){ |n| is_cu(n) }
when "C"; remove_after( seq ){ |n| is_cu(n) }
when "h"; seq.drop(100)
when /[2-9]/
seq.each_slice(cmd.to_i).flat_map{ |i| i[0..-2] }
else
raise "unexpected cmd : #{cmd} in #{s}"
end
end
seq
end
def solve( s, len=10 )
solve_core( s ).first(len).to_a.join(",")
end
DATA.map{ |line|
id, src, expected = line.split(/\s+/ )
actual = solve( src )
ok = actual == expected
puts "***NG*** : %s %s->%s ( %s )" % [ id, src, actual, expected ] unless ok
ok
}.all?.tap{ |r| puts ( r ? "ok" : "NG" ) }
__END__
0 ss6cc24S 1,9,21,30,33,37,42,44,49,56
1 h 101,102,103,104,105,106,107,108,109,110
2 hh 201,202,203,204,205,206,207,208,209,210
3 hhh 301,302,303,304,305,306,307,308,309,310
50 23h465Ssc9CchC 1027,1033,1045,1047,1057,1069,1071,1075,1081,1093
いつも通り、テストデータの大半は省略。
たぶん、遅延評価を前提に無限リストを作って、それをこねると出来上がる、というのが順当な実装だと思う。
遅延評価がない処理系だと固定長で用意していくんだと思うけど、ruby には lazy があるので大丈夫。
実装で手間取ったのは
「無限リストの前に要素を1つ追加する」
という処理を書く部分。
当初はどうせあるだろうと思って調べたんだけど実は存在せず、実装するはめになった。
普通に [1]+lazy_enum
という感じで加算できていいと思うんだけど。
当日罠として機能した三乗根の計算は
(b**(1r/3)).round**3==b
という風にして浮動小数点の計算誤差を回避したんだけど、ruby には Math.cbrt
があることを教えていただいた。
Math.cbrt(100**3) #=> 100.0
(100**3)**(1r/3) #=> 99.99999999999997
Math.cbrt(100.00000000000001**3) #=> 100.00000000000001
(100.00000000000001**3)**(1r/3) #=> 99.99999999999999
という感じ。素晴らしい。
Author And Source
この問題について(第24回オフラインリアルタイムどう書く「多段階選抜」の rubyによる実装), 我々は、より多くの情報をここで見つけました https://qiita.com/Nabetani/items/632bdf35ddccd0d8147d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .