結果

問題 No.5017 Tool-assisted Shooting
ユーザー tomeruntomerun
提出日時 2023-07-16 16:48:59
言語 Crystal
(1.11.2)
結果
AC  
実行時間 1,188 ms / 2,000 ms
コード長 7,207 bytes
コンパイル時間 17,270 ms
コンパイル使用メモリ 262,544 KB
実行使用メモリ 24,408 KB
スコア 4,455,199
平均クエリ数 1000.00
最終ジャッジ日時 2023-07-16 16:50:58
合計ジャッジ時間 108,336 ms
ジャッジサーバーID
(参考情報)
judge13 / judge16
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 868 ms
23,376 KB
testcase_01 AC 1,007 ms
23,628 KB
testcase_02 AC 633 ms
24,276 KB
testcase_03 AC 862 ms
23,400 KB
testcase_04 AC 687 ms
23,400 KB
testcase_05 AC 774 ms
24,036 KB
testcase_06 AC 824 ms
24,360 KB
testcase_07 AC 855 ms
23,976 KB
testcase_08 AC 728 ms
24,036 KB
testcase_09 AC 789 ms
23,400 KB
testcase_10 AC 885 ms
23,844 KB
testcase_11 AC 712 ms
23,844 KB
testcase_12 AC 835 ms
24,024 KB
testcase_13 AC 839 ms
23,364 KB
testcase_14 AC 917 ms
24,396 KB
testcase_15 AC 858 ms
24,336 KB
testcase_16 AC 717 ms
24,048 KB
testcase_17 AC 869 ms
23,424 KB
testcase_18 AC 845 ms
24,036 KB
testcase_19 AC 875 ms
23,532 KB
testcase_20 AC 873 ms
23,364 KB
testcase_21 AC 937 ms
23,376 KB
testcase_22 AC 667 ms
23,424 KB
testcase_23 AC 785 ms
24,024 KB
testcase_24 AC 893 ms
24,024 KB
testcase_25 AC 972 ms
23,376 KB
testcase_26 AC 779 ms
24,060 KB
testcase_27 AC 794 ms
23,856 KB
testcase_28 AC 982 ms
23,412 KB
testcase_29 AC 680 ms
24,348 KB
testcase_30 AC 620 ms
23,532 KB
testcase_31 AC 761 ms
23,520 KB
testcase_32 AC 873 ms
23,412 KB
testcase_33 AC 1,033 ms
24,384 KB
testcase_34 AC 837 ms
23,388 KB
testcase_35 AC 876 ms
24,348 KB
testcase_36 AC 715 ms
24,348 KB
testcase_37 AC 939 ms
24,048 KB
testcase_38 AC 844 ms
24,048 KB
testcase_39 AC 912 ms
24,408 KB
testcase_40 AC 878 ms
24,324 KB
testcase_41 AC 724 ms
24,024 KB
testcase_42 AC 960 ms
23,628 KB
testcase_43 AC 830 ms
23,616 KB
testcase_44 AC 901 ms
24,324 KB
testcase_45 AC 814 ms
24,264 KB
testcase_46 AC 906 ms
23,388 KB
testcase_47 AC 702 ms
23,412 KB
testcase_48 AC 940 ms
23,556 KB
testcase_49 AC 835 ms
23,544 KB
testcase_50 AC 875 ms
24,276 KB
testcase_51 AC 904 ms
24,024 KB
testcase_52 AC 942 ms
23,376 KB
testcase_53 AC 875 ms
23,664 KB
testcase_54 AC 984 ms
23,844 KB
testcase_55 AC 840 ms
23,628 KB
testcase_56 AC 839 ms
23,388 KB
testcase_57 AC 741 ms
24,324 KB
testcase_58 AC 849 ms
23,424 KB
testcase_59 AC 966 ms
23,376 KB
testcase_60 AC 884 ms
23,832 KB
testcase_61 AC 786 ms
24,336 KB
testcase_62 AC 773 ms
23,640 KB
testcase_63 AC 838 ms
23,436 KB
testcase_64 AC 915 ms
23,376 KB
testcase_65 AC 1,188 ms
24,384 KB
testcase_66 AC 979 ms
23,664 KB
testcase_67 AC 868 ms
24,036 KB
testcase_68 AC 840 ms
23,844 KB
testcase_69 AC 900 ms
24,024 KB
testcase_70 AC 818 ms
24,276 KB
testcase_71 AC 843 ms
23,388 KB
testcase_72 AC 653 ms
23,832 KB
testcase_73 AC 850 ms
23,532 KB
testcase_74 AC 699 ms
23,556 KB
testcase_75 AC 911 ms
23,640 KB
testcase_76 AC 912 ms
23,844 KB
testcase_77 AC 993 ms
23,388 KB
testcase_78 AC 839 ms
24,060 KB
testcase_79 AC 822 ms
24,312 KB
testcase_80 AC 901 ms
23,532 KB
testcase_81 AC 742 ms
23,376 KB
testcase_82 AC 790 ms
23,640 KB
testcase_83 AC 811 ms
23,400 KB
testcase_84 AC 870 ms
23,652 KB
testcase_85 AC 879 ms
23,544 KB
testcase_86 AC 914 ms
23,412 KB
testcase_87 AC 779 ms
23,652 KB
testcase_88 AC 978 ms
24,036 KB
testcase_89 AC 832 ms
23,640 KB
testcase_90 AC 916 ms
24,024 KB
testcase_91 AC 1,043 ms
24,024 KB
testcase_92 AC 668 ms
24,072 KB
testcase_93 AC 883 ms
23,628 KB
testcase_94 AC 732 ms
24,348 KB
testcase_95 AC 895 ms
23,544 KB
testcase_96 AC 942 ms
24,264 KB
testcase_97 AC 845 ms
24,312 KB
testcase_98 AC 891 ms
23,376 KB
testcase_99 AC 850 ms
24,060 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

START_TIME = Time.utc.to_unix_ms
TL         = (ENV["TL"]? || 1000).to_i
INF        = 1 << 28
H          = 60
W          = 25
RND        = Random.new(2)

macro debug(msg)
  {% if flag?(:trace) %}
    STDERR.puts({{msg}})
  {% end %}
end

macro debugf(format_string, *args)
  {% if flag?(:trace) %}
    STDERR.printf({{format_string}}, {{*args}})
  {% end %}
end

def crash(msg, caller_line = __LINE__)
  STDERR.puts "[ERROR] line #{caller_line}: #{msg}"
  exit
end

macro assert(cond, msg = "", caller_line = __LINE__)
  {% if flag?(:local) %}
    if !({{cond}})
      crash({{msg}}, {{caller_line}})
    end
  {% end %}
end

record Spawn, h : Int32, p : Int32, x : Int32

class Enemy
  property :h
  getter :p, :ih

  def initialize(@h : Int32, @p : Int32)
    @ih = @h
  end
end

class OnlineJudge
  def input
    n = read_line.to_i
    return nil if n == -1
    return Array.new(n) do
      h, p, x = read_line.split.map(&.to_i)
      Spawn.new(h, p, x)
    end
  end

  def output(dir)
    puts "SRL"[dir]
    STDOUT.flush
  end
end

class LocalJudge
  @p : Array(Int32)

  def initialize
    @p = read_line.split.map(&.to_i)
    @enemies = Array(Array(Enemy?)).new(W) { Array(Enemy?).new(H, nil) }
    @player = 12
    @exp = 0
    @turn = 0
    @defeat = false
    @score = 0
  end

  def input
    W.times do |i|
      @enemies[i][0..(H - 2)] = @enemies[i][1..]
      @enemies[i][-1] = nil
    end
    if @enemies[@player][0]
      @defeat = true
    end
    if @defeat
      debug("defeat at turn #{@turn}")
      return nil
    end
    n = read_line.to_i
    ret = [] of Spawn
    n.times do
      h, p, x = read_line.split.map(&.to_i)
      @enemies[x][H - 1] = Enemy.new(h, p)
      ret << Spawn.new(h, p, x)
    end
    @turn += 1
    return ret
  end

  def output(dir)
    puts "SRL"[dir]
    @player += dir + W
    @player %= W
    if @enemies[@player][0]
      @defeat = true
    else
      1.upto(H - 1) do |i|
        if e = @enemies[@player][i]
          e.h -= @exp // 100 + 1
          if e.h <= 0
            @exp += e.p
            @score += e.ih
            @enemies[@player][i] = nil
          end
          break
        end
      end
    end
  end

  def print
    printf("score=%d\n", @score)
  end
end

#####################
# end of template/lib
#####################

main

def main
  judge = OnlineJudge.new
  {% if flag?(:local) %}
    judge = LocalJudge.new
  {% end %}
  solver = Solver.new(judge)
  solver.solve
  {% if flag?(:local) %}
    judge.as(LocalJudge).print
  {% end %}
end

class Solver(Judge)
  def initialize(@judge : Judge)
    @es = Array(Array(Enemy?)).new(W) { Array(Enemy?).new(H, nil) }
    @px = 12
    @exp = 0
    @atk = 1
    @turn = 0
    @score = 0
    @spawn_cnt = Array(Int32).new(W, 0)
  end

  def solve
    1000.times do
      ss = @judge.input
      if !ss
        debug("score:#{@exp}")
        return
      end
      W.times do |x|
        @es[x].rotate!(1)
        @es[x][H - 1] = nil
      end
      ss.each do |s|
        @es[s.x][H - 1] = Enemy.new(s.h, s.p)
        @spawn_cnt[s.x] += 1
      end
      move = select_move()
      @px = mv(@px, move)
      if @es[@px][0].nil?
        1.upto(H - 1) do |y|
          if e = @es[@px][y]
            debug("attack (#{@px},#{y}) #{e.h}->#{e.h - @atk}")
            e.h -= @atk
            if e.h <= 0
              @exp += e.p
              @score += e.ih
              @atk = 1 + @exp // 100
              @es[@px][y] = nil
            end
            break
          end
        end
      end
      @judge.output(move)
      @turn += 1
    end
    debug("score:#{@score}")
  end

  def spawn_cnt_bonus(x)
    p = (@spawn_cnt[x] + 40) / (@turn + 1000)
    return p * 0.001 * (@turn ** 1.5)
  end

  def near_bonus(y)
    return 0.0005 / (y + 1) * (@turn ** 1.8)
  end

  def select_move
    debug("x:#{@px}")
    best_v = 0.0
    best_move = 0
    need = 0
    sum = 0
    exp = @exp + 100
    1.upto(H - 1) do |ey|
      if e = @es[@px][ey]
        need += (e.h + exp // 100 - 1) // (exp // 100)
        break if need > ey
        dy_b = 0.0
        if exp < 2000 && exp // 100 != (exp + e.p) // 100
          dy_b = -0.9
        end
        exp += e.p
        sum += @turn < 800 ? e.p : e.ih
        eff = sum / (0 + need + dy_b)
        eff += spawn_cnt_bonus(@px)
        eff += near_bonus(ey)
        if eff > best_v
          best_v = eff
          best_move = 0
          debug("best_v:#{eff} #{@px} 0 0")
        end
      end
    end

    {-1, 1}.each do |move|
      v = sim_move(@px, 0, 0, @exp + 100, best_v, move, 0)
      if v > best_v
        best_v = v
        best_move = move
      end

      # nx = mv(@px, move)
      # next if @es[nx][0] || @es[nx][1] && @es[nx][1].not_nil!.h > @atk
      # ny = 0
      # while nx != @px && ny < H - 3
      #   need = 0
      #   sum = 0
      #   exp = @exp + 100
      #   (ny + 1).upto(H - 1) do |ey|
      #     if e = @es[nx][ey]
      #       need += (e.h + exp // 100 - 1) // (exp // 100)
      #       break if need > ey - ny
      #       dy_b = 0.0
      #       if exp < 2000 && exp // 100 != (exp + e.p) // 100
      #         dy_b = -0.9
      #       end
      #       exp += e.p
      #       sum += @turn < 800 ? e.p : e.ih
      #       eff = sum / (ny + need + dy_b)
      #       eff += spawn_cnt_bonus(nx)
      #       eff += near_bonus(ey)
      #       if eff > best_v
      #         best_v = eff
      #         best_move = move
      #         debug("best_v:#{eff} #{nx} #{ny} #{move}")
      #       end
      #     end
      #   end
      #   ny += 1
      #   if @es[nx][ny]
      #     break
      #   end
      #   nnx = mv(nx, move)
      #   next if @es[nnx][ny] || @es[nnx][ny + 1] && @es[nnx][ny + 1].not_nil!.h > @atk
      #   nx = nnx
      # end
    end
    return best_move
  end

  def sim_move(nx, ny, sum_o, exp_o, best_v, move, depth)
    return 0.0 if ny > H - 3
    nx = mv(nx, move)
    return 0.0 if @es[nx][ny] || @es[nx][ny + 1] && @es[nx][ny + 1].not_nil!.h > exp_o // 100
    while ny < H - 3
      need = 0
      sum = sum_o
      exp = exp_o
      (ny + 1).upto(H - 1) do |ey|
        if e = @es[nx][ey]
          need += (e.h + exp // 100 - 1) // (exp // 100)
          break if need > ey - ny
          dy_b = 0.0
          if exp < 2000 && exp // 100 != (exp + e.p) // 100
            dy_b = -0.9
          end
          exp += e.p
          sum += @turn < 800 ? e.p : e.ih
          eff = sum / (ny + need + dy_b)
          eff += spawn_cnt_bonus(nx)
          eff += near_bonus(ey)
          if eff > best_v
            best_v = eff
            # debug("best_v:#{eff} #{nx} #{ny} #{move}")
          end
          if depth <= 0
            {-1, 1}.each do |nmove|
              best_v = {best_v, sim_move(nx, ny + need, sum, exp, best_v, nmove, depth + 1)}.max
            end
          end
        end
      end
      ny += 1
      if @es[nx][ny]
        break
      end
      nnx = mv(nx, move)
      next if @es[nnx][ny] || @es[nnx][ny + 1] && @es[nnx][ny + 1].not_nil!.h > exp_o // 100
      nx = nnx
    end
    return best_v
  end

  def mv(x, d)
    x += d
    if x == -1
      return W - 1
    elsif x == W
      return 0
    else
      return x
    end
  end
end
0