← Home
package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
	"strconv"
)

type Item struct {
	i, j int
	d    int64
}

type PriorityQueue []Item

func (pq PriorityQueue) Len() int           { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool { return pq[i].d < pq[j].d }
func (pq PriorityQueue) Swap(i, j int)      { pq[i], pq[j] = pq[j], pq[i] }
func (pq *PriorityQueue) Push(x interface{}) {
	*pq = append(*pq, x.(Item))
}
func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	item := old[n-1]
	*pq = old[0 : n-1]
	return item
}

type pair struct{ i, j int }

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024)
	scanner.Split(bufio.ScanWords)

	nextInt := func() int {
		scanner.Scan()
		v, _ := strconv.Atoi(scanner.Text())
		return v
	}

	nextString := func() string {
		scanner.Scan()
		return scanner.Text()
	}

	if !scanner.Scan() {
		return
	}
	tCases, _ := strconv.Atoi(scanner.Text())

	dirs4 := [4][2]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}
	dirs8 := [8][2]int{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}

	for t := 0; t < tCases; t++ {
		n := nextInt()
		r := nextInt()
		k := nextInt()

		a := make([][]int, n)
		for i := 0; i < n; i++ {
			a[i] = make([]int, n)
			for j := 0; j < n; j++ {
				a[i][j] = nextInt()
			}
		}

		c := make([]string, n)
		for i := 0; i < n; i++ {
			c[i] = nextString()
		}

		visited := make([][]bool, n)
		for i := 0; i < n; i++ {
			visited[i] = make([]bool, n)
		}

		q := make([]pair, 0, n*n)

		pathExists := func(limit int) bool {
			if a[0][0] > limit || a[r-1][n-1] > limit {
				return false
			}
			for i := 0; i < n; i++ {
				for j := 0; j < n; j++ {
					visited[i][j] = false
				}
			}
			q = q[:0]
			q = append(q, pair{0, 0})
			visited[0][0] = true
			head := 0
			for head < len(q) {
				curr := q[head]
				head++
				if curr.i == r-1 && curr.j == n-1 {
					return true
				}
				for _, dir := range dirs4 {
					ni, nj := curr.i+dir[0], curr.j+dir[1]
					if ni >= 0 && ni < n && nj >= 0 && nj < n && !visited[ni][nj] && a[ni][nj] <= limit {
						visited[ni][nj] = true
						q = append(q, pair{ni, nj})
					}
				}
			}
			return false
		}

		lowM, highM := 1, 1000000
		DM := -1
		for lowM <= highM {
			mid := (lowM + highM) / 2
			if pathExists(mid) {
				DM = mid
				highM = mid - 1
			} else {
				lowM = mid + 1
			}
		}

		reach1 := make([][]bool, n)
		for i := 0; i < n; i++ {
			reach1[i] = make([]bool, n)
		}
		q = q[:0]
		q = append(q, pair{0, 0})
		reach1[0][0] = true
		head := 0
		for head < len(q) {
			curr := q[head]
			head++
			for _, dir := range dirs4 {
				ni, nj := curr.i+dir[0], curr.j+dir[1]
				if ni >= 0 && ni < n && nj >= 0 && nj < n && !reach1[ni][nj] && a[ni][nj] <= DM {
					reach1[ni][nj] = true
					q = append(q, pair{ni, nj})
				}
			}
		}

		reach2 := make([][]bool, n)
		for i := 0; i < n; i++ {
			reach2[i] = make([]bool, n)
		}
		q = q[:0]
		q = append(q, pair{r - 1, n - 1})
		reach2[r-1][n-1] = true
		head = 0
		for head < len(q) {
			curr := q[head]
			head++
			for _, dir := range dirs4 {
				ni, nj := curr.i+dir[0], curr.j+dir[1]
				if ni >= 0 && ni < n && nj >= 0 && nj < n && !reach2[ni][nj] && a[ni][nj] <= DM {
					reach2[ni][nj] = true
					q = append(q, pair{ni, nj})
				}
			}
		}

		inVpath := make([][]bool, n)
		for i := 0; i < n; i++ {
			inVpath[i] = make([]bool, n)
			for j := 0; j < n; j++ {
				if reach1[i][j] && reach2[i][j] {
					inVpath[i][j] = true
				}
			}
		}

		dist := make([][]int64, n)
		for i := 0; i < n; i++ {
			dist[i] = make([]int64, n)
		}
		pq := make(PriorityQueue, 0, n*n)

		check := func(X int) bool {
			for i := 0; i < n; i++ {
				for j := 0; j < n; j++ {
					dist[i][j] = 1e18
				}
			}
			pq = pq[:0]

			for i := 0; i < n; i++ {
				for j := 0; j < n; j++ {
					if X > DM && inVpath[i][j] {
						continue
					}
					var w int64 = 0
					if a[i][j] < X {
						if c[i][j] == '1' {
							w = int64(X - a[i][j])
						} else {
							w = 1e18
						}
					}
					isP1 := (i == 0 || j == 0 || (j == n-1 && i <= r-1))
					if isP1 && w <= int64(k) {
						dist[i][j] = w
						heap.Push(&pq, Item{i, j, w})
					}
				}
			}

			for pq.Len() > 0 {
				curr := heap.Pop(&pq).(Item)
				i, j, d := curr.i, curr.j, curr.d
				if d > dist[i][j] {
					continue
				}

				isP2 := (i == n-1 || (j == n-1 && i >= r-1))
				if isP2 {
					return true
				}

				for _, dir := range dirs8 {
					ni, nj := i+dir[0], j+dir[1]
					if ni >= 0 && ni < n && nj >= 0 && nj < n {
						if X > DM && inVpath[ni][nj] {
							continue
						}
						var w int64 = 0
						if a[ni][nj] < X {
							if c[ni][nj] == '1' {
								w = int64(X - a[ni][nj])
							} else {
								w = 1e18
							}
						}
						if w != 1e18 && d+w <= int64(k) && d+w < dist[ni][nj] {
							dist[ni][nj] = d + w
							heap.Push(&pq, Item{ni, nj, dist[ni][nj]})
						}
					}
				}
			}
			return false
		}

		ansF := 0
		lowF, highF := 1, 2000005
		for lowF <= highF {
			mid := (lowF + highF) / 2
			if check(mid) {
				ansF = mid
				lowF = mid + 1
			} else {
				highF = mid - 1
			}
		}

		fmt.Printf("%d %d\n", DM, ansF)
	}
}