結果
問題 | No.703 ゴミ拾い Easy |
ユーザー | tamura2004 |
提出日時 | 2024-05-30 10:55:32 |
言語 | Crystal (1.11.2) |
結果 |
AC
|
実行時間 | 356 ms / 1,500 ms |
コード長 | 11,195 bytes |
コンパイル時間 | 14,183 ms |
コンパイル使用メモリ | 299,580 KB |
実行使用メモリ | 42,076 KB |
最終ジャッジ日時 | 2024-05-30 10:55:58 |
合計ジャッジ時間 | 22,946 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1 ms
6,812 KB |
testcase_01 | AC | 2 ms
6,816 KB |
testcase_02 | AC | 1 ms
6,940 KB |
testcase_03 | AC | 1 ms
6,940 KB |
testcase_04 | AC | 1 ms
6,944 KB |
testcase_05 | AC | 2 ms
6,944 KB |
testcase_06 | AC | 2 ms
6,944 KB |
testcase_07 | AC | 1 ms
6,944 KB |
testcase_08 | AC | 2 ms
6,944 KB |
testcase_09 | AC | 2 ms
6,944 KB |
testcase_10 | AC | 2 ms
6,944 KB |
testcase_11 | AC | 2 ms
6,944 KB |
testcase_12 | AC | 1 ms
6,940 KB |
testcase_13 | AC | 2 ms
6,940 KB |
testcase_14 | AC | 2 ms
6,948 KB |
testcase_15 | AC | 3 ms
6,940 KB |
testcase_16 | AC | 3 ms
6,940 KB |
testcase_17 | AC | 3 ms
6,940 KB |
testcase_18 | AC | 3 ms
6,944 KB |
testcase_19 | AC | 2 ms
6,944 KB |
testcase_20 | AC | 3 ms
6,940 KB |
testcase_21 | AC | 3 ms
6,940 KB |
testcase_22 | AC | 3 ms
6,944 KB |
testcase_23 | AC | 3 ms
6,940 KB |
testcase_24 | AC | 355 ms
42,028 KB |
testcase_25 | AC | 325 ms
42,076 KB |
testcase_26 | AC | 328 ms
42,012 KB |
testcase_27 | AC | 319 ms
42,020 KB |
testcase_28 | AC | 356 ms
42,000 KB |
testcase_29 | AC | 325 ms
41,980 KB |
testcase_30 | AC | 327 ms
41,960 KB |
testcase_31 | AC | 322 ms
41,964 KB |
testcase_32 | AC | 342 ms
42,040 KB |
testcase_33 | AC | 324 ms
42,024 KB |
testcase_34 | AC | 90 ms
34,752 KB |
testcase_35 | AC | 90 ms
34,668 KB |
testcase_36 | AC | 88 ms
34,740 KB |
testcase_37 | AC | 88 ms
34,764 KB |
testcase_38 | AC | 89 ms
35,264 KB |
testcase_39 | AC | 112 ms
34,732 KB |
testcase_40 | AC | 91 ms
34,728 KB |
testcase_41 | AC | 89 ms
34,736 KB |
testcase_42 | AC | 88 ms
34,660 KB |
testcase_43 | AC | 92 ms
34,680 KB |
testcase_44 | AC | 1 ms
6,940 KB |
testcase_45 | AC | 1 ms
6,940 KB |
testcase_46 | AC | 99 ms
39,396 KB |
testcase_47 | AC | 97 ms
41,992 KB |
testcase_48 | AC | 3 ms
6,940 KB |
testcase_49 | AC | 2 ms
6,940 KB |
ソースコード
# require "crystal/cht" # require "crystal/orderedset" # require "crystal/avl_tree" # AVL木によるOrderedSet class AVLTree(T) getter root : Node(T)? def initialize(@root : Node(T)? = nil) end def includes?(v : T) root.try &.includes?(v) end def insert(v : T) @root = root.try &.insert(v) || Node(T).new(v) end def <<(v : T) insert(v) end def insert_at(i : Int32, v : T) @root = root.try &.insert_at(i, v) || Node(T).new(v) end def []=(i : Int32, v : T) insert_at(i, v) end def delete(v : T) @root = root.try &.delete(v) end def >>(v : T) delete(v) end # v以下(未満)の最大値 # # ``` # tr = [1, 3, 5, 7].to_ordered_set # tr.lower(4) # => 3 # tr.lower(5) # => 5 # tr.lower(5, eq: false) # => 3 # tr.lower(0) # => nil # ``` def lower(v, eq = true) @root.try &.lower(v, eq) end # v以下(未満)の最大のインデックス def lower_index(v, eq = true) @root.try &.lower_index(v, eq) end # v以下(未満)の要素数 def lower_count(v, eq = true) @root.try(&.lower_index(v, eq)).try(&.succ) || 0 end # v以上(より大きい)の最小値 # ``` # tr = [1, 3, 5, 7].to_ordered_set # tr.upper(8) # => nil # tr.upper(5) # => 7 # tr.upper(5, eq: false) # => 5 # ``` def upper(v, eq = true) @root.try &.upper(v, eq) end def upper_index(v, eq = true) @root.try &.upper_index(v, eq) end # v以上(より大きい)要素数 def upper_count(v, eq = true) @root.try(&.upper_index(v, eq)).try { |v| (@root.try(&.size) || 0) - v } || 0 end # 区間の要素数 def count(r : Range(Int::Primitive?, Int::Primitive?)) lo = r.begin || min hi = (r.end || max) return 0 if lo.nil? || hi.nil? eq = !r.excludes_end? lower_count(hi, eq) - lower_count(lo, eq: false) end # 最小の値を持つノード def min_node @root.try &.min_node end # 最小の値 def min @root.try &.min end # 最大の値を持つノード def max_node @root.try &.max_node end # 最大の値 def max @root.try &.max end # 最大値を削除して返す def pop @root, node = root.try &.pop || {nil.as(Node(T)?), nil.as(Node(T)?)} node end # 小さいほうからk番目のノードの値(0-origin) def at(k) @root.try &.at(k) end def [](k) at(k).not_nil! end def size @root.try &.size || 0 end def clear @root = nil end def inspect @root.inspect end def to_a @root.try &.to_a || [] of T end def debug @root.try &.debug(0) end class Node(T) getter val : T getter balance : Int32 getter height : Int32 getter size : Int32 property left : Node(T)? property right : Node(T)? def initialize(@val) @balance = 0 @size = 1 @height = 1 @left = nil @right = nil end def includes?(v : T) if v == val true elsif v < val left.try &.includes?(v) else right.try &.includes?(v) end end # 挿入 def insert(v) return self if v == val if v < val @left = left.try &.insert(v) || Node(T).new(v) else @right = right.try &.insert(v) || Node(T).new(v) end update re_balance end # i番目に挿入 def insert_at(i, v) ord = left_size if i <= ord @left = left.try &.insert_at(i, v) || Node(T).new(v) else @right = right.try &.insert_at(i - ord - 1, v) || Node(T).new(v) end update.re_balance end # 削除 def delete(v) if v == val left.try do |l| @left, node = l.pop node.left, node.right = left, right node.update.re_balance end || right.try do |r| right end || nil elsif v < val @left = left.try &.delete(v) update.re_balance else @right = right.try &.delete(v) update.re_balance end end # v以下(未満)の最大値 def lower(v, eq = true) if val < v || (eq && v == val) right.try(&.lower(v, eq)).try { |v| Math.max(v, val) } || val else left.try &.lower(v, eq) end end # v以下(未満)の最大のインデックス def lower_index(v, eq = true) pos = left_size if val < v || (eq && v == val) right.try(&.lower_index(v, eq)).try(&.+(pos + 1)) || pos else left.try(&.lower_index(v, eq)) end end # v以上(超える)の最小値 def upper(v, eq = true) if v < val || (eq && v == val) left.try(&.upper(v, eq)).try { |v| Math.min(v, val) } || val else right.try &.upper(v, eq) end end # v以上(超える)の最小のインデックス def upper_index(v, eq = true) pos = left_size if val > v || (eq && v == val) left.try(&.upper_index(v, eq)) || pos else right.try(&.upper_index(v, eq)).try(&.+(pos + 1)) end end # 最大値を削除して返す def pop right.try do |r| @right, node = r.pop {update, node} end || {left, self} end # 最小のノード def min_node left.try &.min_node || self end # 最小の値 def min min_node.try &.val end # 最大のノード def max_node right.try &.max_node || self end # 最大の値 def max max_node.try &.val end # 小さいほうからk番目のノードの値(0-origin) def at(k) return at(size + k) if k < 0 ord = left_size if k == ord val elsif k < ord left.try &.at(k) else right.try &.at(k - ord - 1) end end # ノードの状態を更新 def update @height = Math.max(left_height, right_height) + 1 @balance = left_height - right_height @size = left_size + right_size + 1 self end # 回転によりバランスを保つ def re_balance case balance when 2.. if left_balance < 0 @left = left.try &.rotate_left.update end rotate_right.update when ..-2 if right_balance > 0 @right = right.try &.rotate_right.update end rotate_left.update else self end end # 左回転 def rotate_left right.try do |root| root.tap do @right, root.left = root.left, self root.update update end end || self end # 右回転 def rotate_right left.try do |root| root.tap do @left, root.right = root.right, self root.update update end end || self end @[AlwaysInline] def [](k) at(k).not_nil! end {% for dir in %w(left right) %} {% for op in %w(size height balance) %} @[AlwaysInline] private def {{dir.id}}_{{op.id}} {{dir.id}}.try &.{{op.id}} || 0 end {% end %} {% end %} @[AlwaysInline] private def left_to_a left.try &.to_a || [] of T end @[AlwaysInline] private def right_to_a right.try &.to_a || [] of T end def inspect # "(#{val} #{left.inspect} #{right.inspect})".gsub(/nil/, ".") # "(#{left.inspect} #{val} #{right.inspect})".gsub(/nil/, ".") "(#{left.inspect} #{val} #{right.inspect})".gsub(/nil/, ".") end def to_a left_to_a + [val] + right_to_a end def debug(indent = 0) left.try &.debug(indent + 2) puts " " * indent + "#{val}[#{size},#{height},#{balance}]" right.try &.debug(indent + 2) end end end module Indexable(T) def to_avl AVLTree(T).new.tap do |tr| each do |v| tr << v end end end end alias Orderedset = AVLTree module Indexable(T) def to_ordered_set to_avl end end record Line, a : Int64, b : Int64 do include Comparable(Line) # 傾きの降順、y切片の昇順で比較 # / \ # / -> \ # / \ def <=>(other : Line) : Int32 { -a, b } <=> { -other.a, other.b } end def cross(other : Line) : Int64 (other.b - b) // (a - other.a) end def [](x : Int64) a * x + b end end # 動的 Convex Hull Trick # - 直線の追加: O(log N) # - 最小値クエリ: O(log N) class CHT getter lines : Orderedset(Line) delegate to_a, size, to: lines def initialize @lines = Orderedset(Line).new end def add(line : Line) return if lines.includes?(line) # 傾きが同じ直線が既に存在する場合 # y切片が小さい方を残す if left = lines.lower(line, eq: false) if line.a == left.a return unless line.b < left.b lines.delete(left) lines << line end else lines << line end # 傾きが同じ直線が既に存在する場合 # y切片が小さい方を残す if right = lines.upper(line, eq: false) if line.a == right.a return unless line.b < right.b lines.delete(right) lines << line end else lines << line end # 両側に直線が存在する場合 # 交点より小さい場合は追加する if left = lines.lower(line, eq: false) if right = lines.upper(line, eq: false) return unless left.cross(line) < line.cross(right) lines << line end end # 小さい方の直線が交点を上回る場合は削除する if left_right = lines.lower(line, eq: false) while left_left = lines.lower(left_right, eq: false) unless left_left.cross(left_right) < left_right.cross(line) lines.delete(left_right) left_right = left_left else break end end end # 大きい方の直線が交点を上回る場合は削除する if right_left = lines.upper(line, eq: false) while right_right = lines.upper(right_left, eq: false) unless line.cross(right_left) < right_left.cross(right_right) lines.delete(right_left) right_left = right_right else break end end end end def <<(line : Line) add(line) end def min(x : Int64) : Int64 return Int64::MAX if lines.size == 0 return lines[0][x] if lines.size == 1 return Math.min(lines[0][x], lines[1][x]) if lines.size == 2 n = lines.size - 1 i = (0...n).bsearch do |i| lines[i][x] < lines[i + 1][x] end || n lines[i][x] end end # dp[i] := ゴミiを拾うときの最小値(1-indexed) # dp[i] = Min j <= i, dp[j-1] + (x[j] - a[i])^2 + y[j]^2 # dp[i] = a[i]^2 + Min j <= i, Line.new(-2x[j], dp[j-1] + x[j]^2 + y[j]^2)[a[i]] n = gets.to_s.to_i64 a = gets.to_s.split.map(&.to_i64) x = gets.to_s.split.map(&.to_i64) y = gets.to_s.split.map(&.to_i64) dp = Array.new(n+1, 0_i64) cht = CHT.new (0...n).each do |i| cht << Line.new(-2_i64 * x[i], dp[i] + x[i] ** 2 + y[i] ** 2) dp[i+1] = a[i] ** 2 + cht.min(a[i]) end pp dp[-1]