package main
import (
"fmt"
"io"
"os"
)
var buffer []byte
var bufIdx, bufLen int
func readByte() byte {
if bufIdx >= bufLen {
if buffer == nil {
buffer = make([]byte, 65536)
}
n, err := os.Stdin.Read(buffer)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
return 0
}
bufIdx = 0
bufLen = n
}
b := buffer[bufIdx]
bufIdx++
return b
}
func readInt() int {
b := readByte()
for b > 0 && b <= ' ' {
b = readByte()
}
if b == 0 {
return 0
}
res := 0
for b > ' ' {
res = res*10 + int(b-'0')
b = readByte()
}
return res
}
func main() {
n := readInt()
if n == 0 {
return
}
m := readInt()
a_t := make([][]int, m)
for c := 0; c < m; c++ {
a_t[c] = make([]int, n)
}
for r := 0; r < n; r++ {
for c := 0; c < m; c++ {
a_t[c][r] = readInt()
}
}
first_dup := make([][]int, n)
seen_r := make([]int, 160005)
cv_fd := 0
for i1 := 0; i1 < n; i1++ {
first_dup[i1] = make([]int, m)
for c := 0; c < m; c++ {
cv_fd++
fd := n
col := a_t[c]
for r := i1; r < n; r++ {
v := col[r]
if seen_r[v] == cv_fd {
fd = r
break
}
seen_r[v] = cv_fd
}
first_dup[i1][c] = fd
}
}
max_area := 0
seen := make([]uint32, 160005)
current_version := 0
for i1 := 0; i1 < n; i1++ {
if (n-i1)*m <= max_area {
break
}
for i2 := i1; i2 < n; i2++ {
h := i2 - i1 + 1
if h*m <= max_area {
continue
}
max_consec := 0
consec := 0
for c := 0; c < m; c++ {
if first_dup[i1][c] > i2 {
consec++
if consec > max_consec {
max_consec = consec
}
} else {
consec = 0
}
}
if h*max_consec <= max_area {
continue
}
current_version++
cv_shifted := uint32(current_version) << 10
limit := 0
_ = a_t[m-1]
for c := 0; c < m; c++ {
if h*(m-limit) <= max_area {
break
}
val_to_store := cv_shifted | uint32(c+1)
col := a_t[c]
_ = col[i2]
for r := i1; r <= i2; r++ {
v := col[r]
s := seen[v]
seen[v] = val_to_store
if s > cv_shifted {
ls := int(s & 1023)
if ls > limit {
limit = ls
}
}
}
cand := h * (c - limit + 1)
if cand > max_area {
max_area = cand
}
}
}
}
fmt.Println(max_area)
}