```go
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
)
func main() {
// Use buffered I/O for speed
scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanWords)
// Helper function to read the next integer from input
readInt := func() int {
scanner.Scan()
val, _ := strconv.Atoi(scanner.Text())
return val
}
// Read n and k
if !scanner.Scan() {
return
}
nStr := scanner.Text()
n, _ := strconv.Atoi(nStr)
k := readInt()
// Read the skills
a := make([]int, n)
for i := 0; i < n; i++ {
a[i] = readInt()
}
// Sorting allows us to treat teams as contiguous subarrays
sort.Ints(a)
// Precompute the start index for the optimal team ending at each position.
// prevState[i] corresponds to the prefix length before the team ending at a[i-1] starts.
// If the valid balanced team ending at index i-1 is a[left...i-1], then
// the team size is (i - left), and the previous state is dp[left].
// Here i is 1-based (length of prefix), 'left' is 0-based index in a,
// which conveniently maps to the DP state for prefix of length 'left'.
prevState := make([]int, n+1)
left := 0
for i := 0; i < n; i++ {
// Find the smallest 'left' index such that the team a[left...i] is balanced
for a[i]-a[left] > 5 {
left++
}
// The team ending at a[i] starts at a[left].
// In terms of prefix lengths for DP:
// The current prefix length is i+1.
// The team length is (i - left + 1) = (i+1) - left.
// The remaining prefix length is left.
prevState[i+1] = left
}
// DP arrays.
// prevDp[i] stores the max students using t-1 teams with a prefix of length i.
// currDp[i] stores the max students using t teams with a prefix of length i.
prevDp := make([]int, n+1)
currDp := make([]int, n+1)
for t := 1; t <= k; t++ {
for i := 1; i <= n; i++ {
// Option 1: Student i-1 is not the end of the t-th team.
// We carry forward the best result for the current number of teams (t)
// found for the smaller prefix i-1.
opt1 := currDp[i-1]
// Option 2: Student i-1 IS the end of the t-th team.
// This team covers the range a[prevState[i] ... i-1].
// Length of this team is i - prevState[i].
// We add this to the best result for t-1 teams on the remaining prefix (prevState[i]).
opt2 := prevDp[prevState[i]] + (i - prevState[i])
if opt1 > opt2 {
currDp[i] = opt1
} else {
currDp[i] = opt2
}
}
// Swap arrays for the next iteration.
// After swap, prevDp holds the results for 't' teams,
// and currDp is reused for 't+1' teams.
prevDp, currDp = currDp, prevDp
}
// After the loop finishes (t=k), we swapped, so prevDp holds the result for k teams.
fmt.Println(prevDp[n])
}
```