オフラインリアルタイムどう書く E24 の回答
負けました。ほっとんどのテストケースは通るが4つほど通らない、というのがあるというのが時間内の回答です。
が、終わったあとの懇親会でぼーっと考えてたらあそこじゃね?というところに気づいて解けました。そしてその diff がしょーもない。
とりあえず方針はこんな感じです。
単調増加数は各桁に一定の大小関係があるので、桁間で「いくつプラスになるか」というのを割り振るものだと思えばよい。
この捉え方だとある桁数・進数における単調増加数のパターン数をよくある場合の数に落とせる。具体的には、 b-1個のボール(増加分)をr人(桁数)で分けるような何かである。
↓こんな感じ。
5個のボールを2つの仕切りでわける = 4進数2桁における単調増加数のパターン数 こういうマッピングができる ○|○|○○○ -> 12 (5) ○|○○|○○ -> 13 (5) ○○|○○|○ -> 24 (5)
これは nCk で表わせる場合の数である。
これを使うと b 進数 r 桁で表せる単調増加数のパターン数がわかるので m を超えないような最大の r で桁数が確定。次は r 桁のうち idx 番目を num にしたときの単調増加数のパターン数を調べていって桁を確定させると求める数がわかる。
実行速度はたぶんかなりはやい気がします。
$ ruby test.rb (略) ruby test.rb 0.43s user 0.18s system 74% cpu 0.818 total
回答のコードは以下
class Solver def solve(input) @b, @m = input.split(',').map(&:to_i) rank = 1 count = 0 loop do return '-' if rank > (@b - 1) # rank 個の仕切りを n - 1 箇所にいれればよい # rank 末尾と n の末尾になんか変なのいれてることに注意 # → nCrankでよい tmp = count_for(n: @b - 1, k: rank) break if count + tmp >= @m count += tmp rank += 1 end # 桁数確定 idx = 1 num = 1 nums = [] loop do t_n = @b - 1 - num t_k = rank - idx tmp = count_for(n: t_n, k: t_k) if count + tmp >= @m nums << num num += 1 idx += 1 break if nums.size == rank next end count += tmp num += 1 end nums.map { |e| e.to_s(36) }.join('') end def count_for(n:, k:) raise ArgumentError if k > n ret = 1 k.times do |i| ret = ret * (n - i) end k.times do |i| ret = ret / (k - i) end ret.to_i end def incr?(num) tmp = num.to_s(@b).chars return true if tmp.size == 1 tmp.each_cons(2).all? do |c1, c2| c1 < c2 end end end
なお最終コミットはこちらです ↓
fix · hkdnet/misc@2efdfd7 · GitHub
ほんとしょうもない……。