結果

問題 No.5017 Tool-assisted Shooting
ユーザー tomerun
提出日時 2023-07-16 15:31:21
言語 Crystal
(1.14.0)
結果
AC  
実行時間 87 ms / 2,000 ms
コード長 5,018 bytes
コンパイル時間 21,185 ms
コンパイル使用メモリ 256,516 KB
実行使用メモリ 24,480 KB
スコア 4,068,126
平均クエリ数 1000.00
最終ジャッジ日時 2023-07-16 15:31:54
合計ジャッジ時間 32,356 ms
ジャッジサーバーID
(参考情報)
judge13 / judge14
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 100
権限があれば一括ダウンロードができます

ソースコード

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

  def initialize(@h : Int32, @p : Int32)
  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
  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)
    @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
            @enemies[@player][i] = nil
          end
          break
        end
      end
    end
  end

  def print
    printf("score=%d\n", @exp)
  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
    @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
              @atk = 1 + @exp // 100
              @es[@px][y] = nil
            end
            break
          end
        end
      end
      @judge.output(move)
      @turn += 1
    end
    debug("score:#{@exp}")
  end

  def spawn_cnt_bonus(x)
    p = (@spawn_cnt[x] + 4) / (@turn + 100)
    return p * 1
  end

  def select_move
    debug("x:#{@px}")
    best_v = 0.0
    best_move = 0
    1.upto(H - 1) do |ey|
      if e = @es[@px][ey]
        need = (e.h + @atk - 1) // @atk
        if need <= ey - 0
          eff = e.p / (0 + need + 1)
          eff += spawn_cnt_bonus(@px)
          if eff > best_v
            best_v = eff
            best_move = 0
            debug("best_v:#{eff} #{@px} 0 0")
          end
        end
        break
      end
    end

    {-1, 1}.each do |move|
      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
        (ny + 1).upto(H - 1) do |ey|
          if e = @es[nx][ey]
            need = (e.h + @atk - 1) // @atk
            if need <= ey - ny
              eff = e.p / (ny + need + 1)
              eff += spawn_cnt_bonus(nx)
              if eff > best_v
                best_v = eff
                best_move = move
                debug("best_v:#{eff} #{nx} #{ny} #{move}")
              end
            end
            break
          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 mv(x, d)
    x += d
    if x == -1
      return W - 1
    elsif x == W
      return 0
    else
      return x
    end
  end
end
0