結果

問題 No.1288 yuki collection
ユーザー tamura2004tamura2004
提出日時 2022-05-08 11:09:03
言語 Crystal
(1.11.2)
結果
WA  
実行時間 -
コード長 6,499 bytes
コンパイル時間 23,702 ms
コンパイル使用メモリ 265,248 KB
実行使用メモリ 6,392 KB
最終ジャッジ日時 2023-09-22 05:41:10
合計ジャッジ時間 28,353 ms
ジャッジサーバーID
(参考情報)
judge13 / judge11
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 3 ms
4,376 KB
testcase_01 AC 3 ms
4,384 KB
testcase_02 AC 3 ms
4,380 KB
testcase_03 AC 3 ms
4,516 KB
testcase_04 AC 2 ms
4,384 KB
testcase_05 AC 2 ms
4,388 KB
testcase_06 AC 2 ms
4,516 KB
testcase_07 AC 3 ms
4,444 KB
testcase_08 AC 3 ms
4,592 KB
testcase_09 AC 2 ms
4,584 KB
testcase_10 AC 3 ms
4,472 KB
testcase_11 AC 2 ms
4,504 KB
testcase_12 AC 3 ms
4,540 KB
testcase_13 AC 188 ms
6,356 KB
testcase_14 AC 200 ms
6,292 KB
testcase_15 AC 150 ms
6,296 KB
testcase_16 AC 155 ms
6,256 KB
testcase_17 AC 203 ms
6,240 KB
testcase_18 WA -
testcase_19 AC 196 ms
6,268 KB
testcase_20 AC 218 ms
6,352 KB
testcase_21 AC 258 ms
6,392 KB
testcase_22 AC 260 ms
6,200 KB
testcase_23 AC 256 ms
6,348 KB
testcase_24 WA -
testcase_25 WA -
testcase_26 WA -
testcase_27 AC 108 ms
6,280 KB
testcase_28 AC 126 ms
6,292 KB
testcase_29 WA -
testcase_30 AC 9 ms
5,464 KB
testcase_31 AC 14 ms
5,752 KB
testcase_32 AC 14 ms
5,972 KB
testcase_33 AC 232 ms
6,316 KB
testcase_34 AC 272 ms
6,276 KB
testcase_35 AC 256 ms
6,284 KB
testcase_36 AC 157 ms
6,140 KB
testcase_37 AC 166 ms
6,132 KB
testcase_38 AC 62 ms
5,908 KB
testcase_39 AC 61 ms
5,712 KB
testcase_40 AC 4 ms
5,264 KB
testcase_41 AC 2 ms
4,416 KB
testcase_42 AC 2 ms
4,420 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

macro make_array(value, *dims)
  {% for dim in dims %} Array.new({{dim}}) { {% end %}
    {{ value }}
  {% for dim in dims %} } {% end %}
end


# require "crystal/weighted_flow_graph/min_cost_flow"

# require "crystal/weighted_flow_graph/graph"
module WeightedFlowGraph
  class Edge
    getter to : Int32
    property rev : Int32
    property cap : Int64
    property cost : Int64
  
    def initialize(@to, @rev, @cap, @cost)
    end
  
    def inspect(io)
      io << "{to: #{@to}, rev: #{@rev}, cap: #{@cap}, cost: #{@cost}}"
    end
  end
  
  class Graph
    getter n : Int32
    getter g : Array(Array(Edge))
    getter pos : Array(Tuple(Int32, Int32))
    delegate "[]", to: g
  
    
    def initialize(n)
      @n = n.to_i
      @pos = [] of Tuple(Int32, Int32)
      @g = Array(Array(Edge)).new(@n) { [] of Edge }
    end
    
    def add(v, nv, cap, cost, origin = 0) : Int32
      v = v.to_i - origin
      nv = nv.to_i - origin
      cap = cap.to_i64
      cost = cost.to_i64

      edge_number = pos.size
      pos << {v, g[v].size}
      
      rev_v = g[v].size
      rev_nv = g[nv].size
      rev_nv += 1 if v == nv

      g[v] << Edge.new(nv, rev_nv, cap, cost)
      g[nv] << Edge.new(v, rev_v, 0i64, -cost)
      
      edge_number
    end
    
    def get_edge(i)
      _e = g[pos[i][0]][pos[i][1]]
      _re = g[_e.to][_e.rev]
      {pos[i][0], _e.to, _e.cap + _re.cap, _re.cap, _e.cost}
    end
    
    def edges
      pos.map do |(from, id)|
        _e = g[from][id]
        _re = g[_e.to][_e.rev]
        {from, _e.to, _e.cap + _re.cap, _re.cap, _e.cost}
      end
    end

    def debug(origin = 0)
      File.open("debug.dot", "w") do |fh|
        fh.puts "digraph tree {"
        edges.each do |v, nv, cap, flow, cost|
          v += origin
          nv += origin
          fh.puts "#{v} -> #{nv} [label=\"#{cap}[#{flow}],#{cost}\"]"
        end
        fh.puts "}"
      end
      puts `cat debug.dot | graph-easy --from=dot --as_ascii`
    end
  end
end


# require "crystal/priority_queue"
# プライオリティキュー
class PriorityQueue(T)
  getter f : T, T -> Bool
  getter a : Array(T)

  delegate size, to: a
  delegate empty?, to: a
  delegate "[]", to: a
  # forward_missing_to a

  def self.lesser
    new { |a,b| a > b }
  end

  def self.greater
    new { |a,b| a < b }
  end

  def initialize(&block : T, T -> Bool)
    @f = block
    @a = Array(T).new
  end

  def initialize
    @f = ->(a : T, b : T) { a < b }
    @a = Array(T).new
  end

  def <<(v : T)
    @a << v
    fixup(a.size - 1)
  end

  def pop : T
    ret = a[0]
    last = a.pop
    if a.size > 0
      a[0] = last
      fixdown
    end
    ret
  end

  def fixup(i : Int32)
    j = up(i)
    while i > 0 && comp j, i
      a.swap i, j
      i, j = j, up(j)
    end
  end

  def fixdown
    i = 0
    while lo(i) < a.size
      if hi(i) < a.size && comp lo(i), hi(i)
        j = hi(i)
      else
        j = lo(i)
      end
      break if comp j, i
      a.swap i, j
      i = j
    end
  end

  @[AlwaysInline]
  def comp(i, j)
    f.call a[i], a[j]
  end
  
  @[AlwaysInline]
  def lo(i)
    i * 2 + 1
  end
  
  @[AlwaysInline]
  def hi(i)
    i * 2 + 2
  end
  
  @[AlwaysInline]
  def up(i)
    (i - 1) >> 1
  end
end

alias PQ = PriorityQueue

module WeightedFlowGraph
  class MinCostFlow
    getter g : Graph
    getter pv : Array(Int32)
    getter pe : Array(Int32)
    getter dual : Array(Int64)
    delegate :pos, :n, to: g
    
    def initialize(@g)
      @pv = Array(Int32).new(n, 0)
      @pe = Array(Int32).new(n, 0)
      @dual = Array(Int64).new(n, 0)
    end
  
    def solve(s, t, flow_limit = Int64::MAX)
      slope(s, t, flow_limit).last
    end
  
    def dual_ref(s, t)
      dist = Array.new(n, Int64::MAX)
      pv.fill(-1)
      pe.fill(-1)
      seen = Array(Bool).new(n, false)
  
      que = PriorityQueue(Tuple(Int64, Int32)).lesser
      dist[s] = 0_i64
      que << {0_i64, s}
  
      while que.size > 0
        d, v = que.pop
        next if seen[v]
  
        seen[v] = true
        break if v == t
  
        g[v].each_with_index do |e, i|
          nv, cap, cost = e.to, e.cap, e.cost
          next if seen[nv] || cap == 0
  
          n_cost = cost - dual[nv] + dual[v]
          next unless dist[nv] - dist[v] > n_cost
  
          dist[nv] = dist[v] + n_cost
          pv[nv] = v
          pe[nv] = i
          que << {dist[nv], nv}
        end
      end
  
      return false unless seen[t]
  
      n.times do |i|
        next unless seen[i]
  
        dual[i] -= dist[t] - dist[i]
      end
  
      true
    end
  
    def slope(s = 0, t = n - 1, flow_limit = Int64::MAX)
      s = s.to_i
      t = t.to_i

      flow = 0_i64
      cost = 0_i64
      prev_cost = -1
      result = [{flow, cost}]
  
      while flow < flow_limit
        break unless dual_ref(s, t)
  
        c = flow_limit - flow
        v = t
        while v != s
          c = g[pv[v]][pe[v]].cap if c > g[pv[v]][pe[v]].cap
          v = pv[v]
        end
  
        v = t
        while v != s
          e = g[pv[v]][pe[v]]
          e.cap -= c
          g[v][e.rev].cap += c
          v = pv[v]
        end
  
        d = -dual[s]
        flow += c
        cost += c * d
        result.pop if prev_cost == d
        result << {flow, cost}
        prev_cost = d
      end
  
      result
    end
  end
end

include WeightedFlowGraph

enum C
  Y
  U
  K
  I
end

n = gets.to_s.to_i
s = gets.to_s.chars.map do |c|
  case c
  when 'y' then C::Y
  when 'u' then C::U
  when 'k' then C::K
  when 'i' then C::I
  else          raise "bad"
  end
end
v = gets.to_s.split.map(&.to_i64)

g = Graph.new(n + 2)
root = n
goal = n + 1
INF = 1e5.to_i64
MAX = 1e9.to_i64

# 先頭のyにrootから辺を貼る
n.times do |i|
  if s[i].y?
    g.add root, i, INF, 0
    break
  end
end

# 次の出現位置を事前計算
nex = make_array(-1, n, 4)
nex[-1][s[-1].value] = n - 1
(0...n - 1).reverse_each do |i|
  4.times { |j| nex[i][j] = nex[i + 1][j] }
  nex[i][s[i].value] = i
end

# 隣接する同じ文字に辺を貼る
(0...n-1).each do |i|
  j = nex[i+1][s[i].value]
  next if j == -1
  g.add i, j, INF, 0
end

# y,u,kからu,k,iへ辺を貼る
(0...n-1).each do |i|
  j = s[i].value + 1
  next if j == 4
  if nex[i+1][j] != -1
    g.add i, nex[i+1][j], 1, MAX - v[i]
  end
end

# iからgoalへ辺を貼る
n.times do |i|
  next unless s[i].i?
  g.add i, goal, 1, MAX - v[i]
end

# g.debug
flow, cost = MinCostFlow.new(g).solve(root, goal, n)
ans = flow * MAX * 4 - cost
pp ans
0