結果
| 問題 |
No.1288 yuki collection
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2022-05-08 11:09:03 |
| 言語 | Crystal (1.14.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 6,499 bytes |
| コンパイル時間 | 15,031 ms |
| コンパイル使用メモリ | 304,392 KB |
| 実行使用メモリ | 6,944 KB |
| 最終ジャッジ日時 | 2024-07-07 22:21:37 |
| 合計ジャッジ時間 | 18,766 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 35 WA * 5 |
ソースコード
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