← Home
```go
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

type Point struct {
	r, c int
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)

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

	n := scanInt()
	m := scanInt()
	r := scanInt()

	grid := make([][]int, n+1)
	for i := 1; i <= n; i++ {
		grid[i] = make([]int, m+1)
		for j := 1; j <= m; j++ {
			grid[i][j] = scanInt()
		}
	}

	pref := make([][]int, n+1)
	for i := 0; i <= n; i++ {
		pref[i] = make([]int, m+1)
	}
	for i := 1; i <= n; i++ {
		for j := 1; j <= m; j++ {
			pref[i][j] = pref[i-1][j] + pref[i][j-1] - pref[i-1][j-1] + grid[i][j]
		}
	}

	rowWidth := make([]int, 2*r+1)
	rSq := r * r
	for dx := -r; dx <= r; dx++ {
		dy := 0
		for (dy+1)*(dy+1)+dx*dx <= rSq {
			dy++
		}
		rowWidth[dx+r] = dy
	}

	groups := make(map[int][]Point)
	minR, maxR := r+1, n-r
	minC, maxC := r+1, m-r

	if minR > maxR || minC > maxC {
		fmt.Println("0 0")
		return
	}

	for i := minR; i <= maxR; i++ {
		for j := minC; j <= maxC; j++ {
			sum := 0
			for dx := -r; dx <= r; dx++ {
				dy := rowWidth[dx+r]
				r1 := i + dx
				c1 := j - dy
				c2 := j + dy
				seg := pref[r1][c2] - pref[r1][c1-1] - pref[r1-1][c2] + pref[r1-1][c1-1]
				sum += seg
			}
			groups[sum] = append(groups[sum], Point{i, j})
		}
	}

	var keys []int
	for k := range groups {
		keys = append(keys, k)
	}
	sort.Sort(sort.Reverse(sort.IntSlice(keys)))

	bestSum := -1
	var bestCount int64 = 0

	marked := make([][]bool, n+1)
	for i := range marked {
		marked[i] = make([]bool, m+1)
	}

	for i := 0; i < len(keys); i++ {
		valA := keys[i]
		if bestSum != -1 && 2*valA < bestSum {
			break
		}

		for j := i; j < len(keys); j++ {
			valB := keys[j]
			currentSum := valA + valB
			if bestSum != -1 && currentSum < bestSum {
				break
			}

			listA := groups[valA]
			listB := groups[valB]

			pairs := countDisjoint(listA, listB, i == j, r, n, m, marked)

			if pairs > 0 {
				if currentSum > bestSum {
					bestSum = currentSum
					bestCount = pairs
				} else if currentSum == bestSum {
					bestCount += pairs
				}
			}
		}
	}

	if bestSum == -1 {
		fmt.Println("0 0")
	} else {
		fmt.Println(bestSum, bestCount)
	}
}

func countDisjoint(A, B []Point, sameGroup bool, r, n, m int, marked [][]bool) int64 {
	limitSq := 4 * r * r
	lenA := int64(len(A))
	lenB := int64(len(B))

	scanArea := int64(13 * r * r)
	if scanArea > int64(n*m) {
		scanArea = int64(n * m)
	}

	useScan := false
	if sameGroup {
		useScan = scanArea < lenA
	} else {
		useScan = scanArea < lenB
	}

	var intersecting int64 = 0

	if !useScan {
		if sameGroup {
			for i := 0; i < len(A); i++ {
				p1 := A[i]
				for k := i + 1; k < len(A); k++ {
					p2 := A[k]
					dr := p1.r - p2.r
					dc := p1.c - p2.c
					if dr*dr+dc*dc <= limitSq {
						intersecting++
					}
				}
			}
			total := lenA * (lenA - 1) / 2
			return total - intersecting
		} else {
			for _, p1 := range A {
				for _, p2 := range B {
					dr := p1.r - p2.r
					dc := p1.c - p2.c
					if dr*dr+dc*dc <= limitSq {
						intersecting++
					}
				}
			}
			total := lenA * lenB
			return total - intersecting
		}
	} else {
		for _, p := range B {
			marked[p.r][p.c] = true
		}

		twoR := 2 * r
		for _, p := range A {
			rMin := p.r - twoR
			if rMin < 1 {
				rMin = 1
			}
			rMax := p.r + twoR
			if rMax > n {
				rMax = n
			}

			for rr := rMin; rr <= rMax; rr++ {
				dr := rr - p.r
				rem := limitSq - dr*dr
				if rem < 0 {
					continue
				}

				cMin := p.c - twoR
				if cMin < 1 {
					cMin = 1
				}
				cMax := p.c + twoR
				if cMax > m {
					cMax = m
				}

				for cc := cMin; cc <= cMax; cc++ {
					if marked[rr][cc] {
						dc := cc - p.c
						if dc*dc <= rem {
							intersecting++
						}
					}
				}
			}
		}

		for _, p := range B {
			marked[p.r][p.c] = false
		}

		if sameGroup {
			realIntersecting := (intersecting - lenA) / 2
			total := lenA * (lenA - 1) / 2
			return total - realIntersecting
		} else {
			total := lenA * lenB
			return total - intersecting
		}
	}
}
```