Problem:
Score : 100 points

Problem Statement

You are given a grid of N rows and M columns. The square at the i-th row and j-th column will be denoted as (i,j).
A nonnegative integer A_{i,j} is written for each square (i,j).

You choose some of the squares so that each row and column contains at most K chosen squares.
Under this constraint, calculate the maximum value of the sum of the integers written on the chosen squares.
Additionally, calculate a way to choose squares that acheives the maximum.

Constraints

1 \leq N \leq 50

1 \leq K \leq N

0 \leq A_{i,j} \leq 10^9

All values in Input are integer.

Input

Input is given from Standard Input in the following format:

N K
A_{1,1} A_{1,2} \cdots A_{1,N}
A_{2,1} A_{2,2} \cdots A_{2,N}
\vdots
A_{N,1} A_{N,2} \cdots A_{N,N}

Output

On the first line, print the maximum value of the sum of the integers written on the chosen squares.

On the next N lines, print a way that achieves the maximum.

Precisely, output the strings t_1,t_2,\cdots,t_N, that satisfies t_{i,j}=X if you choose (i,j) and t_{i,j}=. otherwise.

You may print any way to choose squares that maximizes the sum.

Sample Input 1

3 1
5 3 2
1 4 8
7 6 9

Sample Output 1

19
X..
..X
.X.

Sample Input 2

3 2
10 10 1
10 10 1
1 1 10

Sample Output 2

50
XX.
XX.
..X

Solution in Go (1.14.1) (judge verdict: Accepted)

package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"strconv"
	"strings"
)

func configure(scanner *bufio.Scanner) {
	scanner.Split(bufio.ScanWords)
	scanner.Buffer(make([]byte, 1000005), 1000005)
}
func getNextString(scanner *bufio.Scanner) string {
	scanned := scanner.Scan()
	if !scanned {
		panic("scan failed")
	}
	return scanner.Text()
}
func getNextInt(scanner *bufio.Scanner) int {
	i, _ := strconv.Atoi(getNextString(scanner))
	return i
}
func getNextInt64(scanner *bufio.Scanner) int64 {
	i, _ := strconv.ParseInt(getNextString(scanner), 10, 64)
	return i
}
func getNextFloat64(scanner *bufio.Scanner) float64 {
	i, _ := strconv.ParseFloat(getNextString(scanner), 64)
	return i
}
func main() {
	fp := os.Stdin
	wfp := os.Stdout
	extra := 0
	if os.Getenv("I") == "IronMan" {
		fp, _ = os.Open(os.Getenv("END_GAME"))
		extra = 100
	}
	scanner := bufio.NewScanner(fp)
	configure(scanner)
	writer := bufio.NewWriter(wfp)
	defer func() {
		r := recover()
		if r != nil {
			fmt.Fprintln(writer, r)
		}
		writer.Flush()
	}()
	solve(scanner, writer)
	for i := 0; i < extra; i++ {
		fmt.Fprintln(writer, "-----------------------------------")
		solve(scanner, writer)
	}
}
func solve(scanner *bufio.Scanner, writer *bufio.Writer) {
	n := getNextInt(scanner)
	k := getNextInt(scanner)
	g := NewMcfGraph64(n<<1 + 2)
	s := n << 1
	t := s + 1
	const Big = 1000000000
	g.AddEdge(s, t, int64(n)*int64(k), Big)
	for i := 0; i < n; i++ {
		g.AddEdge(s, i, int64(k), 0)
		g.AddEdge(n+i, t, int64(k), 0)
	}
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			a := getNextInt64(scanner)
			g.AddEdge(i, n+j, 1, Big-a)
		}
	}
	result := g.FlowWithLimit(s, t, int64(n)*int64(k))
	fmt.Fprintln(writer, int64(n)*int64(k)*Big-result[1])
	grid := makeGrid(n, n)
	for i := 0; i < n; i++ {
		for j := 0; j < n; j++ {
			grid[i][j] = "."
		}
	}
	for _, e := range g.Edges() {
		if e.From == s || e.To == t || e.FLow == 0 {
			continue
		}
		grid[e.From][e.To-n] = "X"
	}
	for i := 0; i < n; i++ {
		fmt.Fprintln(writer, strings.Join(grid[i], ""))
	}
}
func makeGrid(h, w int) [][]string {
	index := make([][]string, h, h)
	data := make([]string, h*w, h*w)
	for i := 0; i < h; i++ {
		index[i] = data[i*w : (i+1)*w]
	}
	return index
}

type edge struct {
	To, Rev   int
	Cap, Cost int64
}

// Edge64 for McfGraph64
type Edge64 struct {
	From, To        int
	Cap, FLow, Cost int64
}

// McfGraph64 solves minimum-cost flow problem.
type McfGraph64 struct {
	n   int
	pos [][2]int
	g   [][]*edge
}

// NewMcfGraph64 creates a graph of n vertices and 0 edges.
func NewMcfGraph64(n int) *McfGraph64 {
	return &McfGraph64{
		n: n,
		g: make([][]*edge, n),
	}
}

// AddEdge adds an edge oriented from from to to with capacity cap and cost cost.
// It returns an integer k such that this is the k-th edge that is added.
func (m *McfGraph64) AddEdge(from, to int, cap, cost int64) int {
	ps := len(m.pos)
	m.pos = append(m.pos, [2]int{from, len(m.g[from])})
	m.g[from] = append(m.g[from], &edge{
		To:   to,
		Rev:  len(m.g[to]),
		Cap:  cap,
		Cost: cost,
	})
	m.g[to] = append(m.g[to], &edge{
		To:   from,
		Rev:  len(m.g[from]) - 1,
		Cap:  0,
		Cost: -cost,
	})
	return ps
}

// GetEdge returns the current internal state of the edges.
// The edges are ordered in the same order as added by add_edge.
func (m *McfGraph64) GetEdge(i int) *Edge64 {
	e := m.g[m.pos[i][0]][m.pos[i][1]]
	re := m.g[e.To][e.Rev]
	return &Edge64{
		From: m.pos[i][0],
		To:   e.To,
		Cap:  e.Cap + re.Cap,
		FLow: re.Cap,
		Cost: e.Cost,
	}
}

// Edges returns the current internal state of the edges.
// The edges are ordered in the same order as added by add_edge.
func (m *McfGraph64) Edges() []*Edge64 {
	ps := len(m.pos)
	result := make([]*Edge64, ps)
	for i := 0; i < ps; i++ {
		result[i] = m.GetEdge(i)
	}
	return result
}

// Flow augments the flow from s to t as much as possible.
// It returns the amount of the flow and the cost.
// It augments the s-t flow as much as possible.
func (m *McfGraph64) Flow(s, t int) [2]int64 {
	return m.FlowWithLimit(s, t, math.MaxInt64)
}

// FlowWithLimit augments the flow from s to t as much as possible.
// It returns the amount of the flow and the cost.
// It augments the s-t flow as much as possible, until reaching the amount of flow_limit.
func (m *McfGraph64) FlowWithLimit(s, t int, flowLimit int64) [2]int64 {
	sl := m.SlopeWithLimit(s, t, flowLimit)
	return sl[len(sl)-1]
}

// Slope returns the list of the changepoints
// Let g be a function such that g(x) is the cost of the minimum cost s-t flow when the amount of the flow is exactly x.
// g is known to be piecewise linear.
// It returns g as the list of the changepoints, that satisfies the followings.
// The first element of the list is (0, 0).
// Both of [0] and [1] are strictly increasing.
// No three changepoints are on the same line.
// The last element of the list is (x, g(x)), where x is the maximum amount of the s-t flow.
func (m *McfGraph64) Slope(s, t int) [][2]int64 {
	return m.SlopeWithLimit(s, t, math.MaxInt64)
}

// SlopeWithLimit returns the list of the changepoints
// Let g be a function such that g(x) is the cost of the minimum cost s-t flow when the amount of the flow is exactly x.
// g is known to be piecewise linear.
// It returns g as the list of the changepoints, that satisfies the followings.
// The first element of the list is (0, 0).
// Both of [0] and [1] are strictly increasing.
// No three changepoints are on the same line.
// The last element of the list is (y, g(y)), where y = min(x, flow_limit).
func (m *McfGraph64) SlopeWithLimit(s, t int, flowLimit int64) [][2]int64 {
	// variants (C = maxcost):
	// -(n-1)C <= dual[s] <= dual[i] <= dual[t] = 0
	// reduced cost (= e.cost + dual[e.from] - dual[e.to]) >= 0 for all edge
	n := m.n
	dual := make([]int64, n)
	dist := make([]int64, n)
	pv := make([]int, n)
	pe := make([]int, n)
	vis := make([]bool, n)
	dualRef := func() bool {
		for i := 0; i < n; i++ {
			dist[i] = math.MaxInt64
			pv[i] = -1
			pe[i] = -1
			vis[i] = false
		}
		dist[s] = 0
		que := make(PriorityQueue, 0)
		que.Push(&Q{Key: 0, To: s})
		for len(que) > 0 {
			v := que[0].To
			que.Pop()
			if vis[v] {
				continue
			}
			vis[v] = true
			if v == t {
				break
			}
			// dist[v] = shortest(s, v) + dual[s] - dual[v]
			// dist[v] >= 0 (all reduced cost are positive)
			// dist[v] <= (n-1)C
			for i := 0; i < len(m.g[v]); i++ {
				e := m.g[v][i]
				if vis[e.To] || e.Cap == 0 {
					continue
				}
				// |-dual[e.to] + dual[v]| <= (n-1)C
				// cost <= C - -(n-1)C + 0 = nC
				cost := e.Cost - dual[e.To] + dual[v]
				if dist[e.To]-dist[v] > cost {
					dist[e.To] = dist[v] + cost
					pv[e.To] = v
					pe[e.To] = i
					que.Push(&Q{Key: dist[e.To], To: e.To})
				}
			}
		}
		if !vis[t] {
			return false
		}
		for v := 0; v < n; v++ {
			if !vis[v] {
				continue
			}
			// dual[v] = dual[v] - dist[t] + dist[v]
			//         = dual[v] - (shortest(s, t) + dual[s] - dual[t]) + (shortest(s, v) + dual[s] - dual[v])
			//         = - shortest(s, t) + dual[t] + shortest(s, v)
			//         = shortest(s, v) - shortest(s, t) >= 0 - (n-1)C
			dual[v] -= dist[t] - dist[v]
		}
		return true
	}
	var flow, cost, prevCost int64
	prevCost = -1
	result := make([][2]int64, 0)
	result = append(result, [2]int64{flow, cost})
	for flow < flowLimit {
		if !dualRef() {
			break
		}
		c := flowLimit - flow
		for v := t; v != s; v = pv[v] {
			if c > m.g[pv[v]][pe[v]].Cap {
				c = m.g[pv[v]][pe[v]].Cap
			}
		}
		for v := t; v != s; v = pv[v] {
			e := m.g[pv[v]][pe[v]]
			e.Cap -= c
			m.g[v][e.Rev].Cap += c
		}
		d := -dual[s]
		flow += c
		cost += c * d
		if prevCost == d {
			result = result[:len(result)-1]
		}
		result = append(result, [2]int64{flow, cost})
	}
	return result
}

type Q struct {
	Key int64
	To  int
}
type PriorityQueue []*Q

func (p PriorityQueue) less(i, j int) bool {
	return p[i].Key < p[j].Key
}
func (p PriorityQueue) swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}
func (p *PriorityQueue) Push(q *Q) {
	n := len(*p)
	*p = append(*p, q)
	for n > 0 && p.less(n, (n-1)>>1) {
		p.swap(n, (n-1)>>1)
		n = (n - 1) >> 1
	}
}
func (p *PriorityQueue) Pop() *Q {
	old := *p
	x := old[0]
	n := len(old) - 1
	old.swap(0, n)
	*p = (*p)[:n]
	loop := true
	for i := 0; i < n && loop; {
		l := i<<1 + 1
		r := i<<1 + 2
		switch {
		case r < n && p.less(r, l) && p.less(r, i):
			p.swap(i, r)
			i = r
		case l < n && p.less(l, i):
			p.swap(i, l)
			i = l
		default:
			loop = false
		}
	}
	return x
}
func (p *PriorityQueue) Peek() *Q {
	return (*p)[0]
}