# frozen_string_literal: true

# Priority Queue
# Reference: https://github.com/python/cpython/blob/master/Lib/heapq.py
class PriorityQueue
  # By default, the priority queue returns the maximum element first.
  # If a block is given, the priority between the elements is determined with it.
  # For example, the following block is given, the priority queue returns the minimum element first.
  # `PriorityQueue.new { |x, y| x < y }`
  #
  # A heap is an array for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for all k, counting elements from 0.
  def initialize(array = [], &comp)
    @heap = array
    @comp = comp || proc { |x, y| x > y }
    heapify
  end

  attr_reader :heap

  # Push new element to the heap.
  def push(item)
    shift_down(0, @heap.push(item).size - 1)
  end

  alias << push
  alias append push

  # Pop the element with the highest priority.
  def pop
    latest = @heap.pop
    return latest if empty?

    ret_item = heap[0]
    heap[0] = latest
    shift_up(0)
    ret_item
  end

  # Get the element with the highest priority.
  def get
    @heap[0]
  end

  alias top get

  # Returns true if the heap is empty.
  def empty?
    @heap.empty?
  end

  private

  def heapify
    (@heap.size / 2 - 1).downto(0) { |i| shift_up(i) }
  end

  def shift_up(pos)
    end_pos = @heap.size
    start_pos = pos
    new_item = @heap[pos]
    left_child_pos = 2 * pos + 1

    while left_child_pos < end_pos
      right_child_pos = left_child_pos + 1
      if right_child_pos < end_pos && @comp.call(@heap[right_child_pos], @heap[left_child_pos])
        left_child_pos = right_child_pos
      end
      # Move the higher priority child up.
      @heap[pos] = @heap[left_child_pos]
      pos = left_child_pos
      left_child_pos = 2 * pos + 1
    end
    @heap[pos] = new_item
    shift_down(start_pos, pos)
  end

  def shift_down(star_pos, pos)
    new_item = @heap[pos]
    while pos > star_pos
      parent_pos = (pos - 1) >> 1
      parent = @heap[parent_pos]
      break if @comp.call(parent, new_item)

      @heap[pos] = parent
      pos = parent_pos
    end
    @heap[pos] = new_item
  end
end

HeapQueue = PriorityQueue

# Min Cost Flow Grapsh
class MinCostFlow
  Edge = Struct.new(:to, :rev, :cap, :cost)

  def initialize(n)
    @n    = n
    @pos  = []
    @g    = Array.new(n) { [] }
    @pv   = Array.new(n)
    @pe   = Array.new(n)
    @dual = Array.new(n) { 0 }
  end

  def add_edge(from, to, cap, cost)
    edge_number = @pos.size

    @pos << [from, @g[from].size]

    from_id = @g[from].size
    to_id   = @g[to].size
    to_id += 1 if from == to
    @g[from] << Edge.new(to, to_id, cap, cost)
    @g[to]   << Edge.new(from, from_id, 0, -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
  alias edge get_edge
  alias [] get_edge

  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 flow(s, t, flow_limit = Float::MAX)
    slope(s, t, flow_limit).last
  end

  def dual_ref(s, t)
    dist = Array.new(@n, Float::MAX)
    @pv.fill(-1)
    @pe.fill(-1)
    vis = Array.new(@n, false)

    que = PriorityQueue.new { |par, chi| par[0] < chi[0] }
    dist[s] = 0
    que.push([0, s])

    while (v = que.pop)
      v = v[1]

      next if vis[v]

      vis[v] = true
      break if v == t

      @g[v].size.times do |i|
        e = @g[v][i]
        next if vis[e.to] || e.cap == 0

        cost = e.cost - @dual[e.to] + @dual[v]
        next unless dist[e.to] - dist[v] > cost

        dist[e.to] = dist[v] + cost
        @pv[e.to] = v
        @pe[e.to] = i
        que.push([dist[e.to], e.to])
      end
    end

    return false unless vis[t]

    @n.times do |i|
      next unless vis[i]

      @dual[i] -= dist[t] - dist[i]
    end

    true
  end

  def slope(s, t, flow_limit = Float::MAX)
    flow = 0
    cost = 0
    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

MCF      = MinCostFlow
MCFGraph = MinCostFlow

n, k = gets.split.map &:to_i
a = $<.map{ |e| e.split.map &:to_i }

g = MinCostFlow.new(2*n+2)
s, t = 2*n, 2*n+1
inf = 10**9

n.times{ |i|
  g.add_edge(s, i, k, 0)
  g.add_edge(i, t, k, inf)
  g.add_edge(n+i, t, k, 0)
}
n.times{ |i|
  n.times{ |j|
    g.add_edge(i, n+j, 1, inf-a[i][j])
  }
}

puts inf*n*k - g.flow(s, t)[1]

ans = (0 ... n).map{ '.' * n }
g.edges.each{ |from, to, cap, flow, _|
  next if from==s || to==t
  ans[from][to-n] = cap==flow ? 'X' : '.'
}

ans.each{ |s| puts s }


Measured memory_bytes: 15304