```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
}
}
}
```