You are given matrix a of size n × m, its elements are integers. We will assume that the rows of the matrix are numbered from top to bottom from 1 to n, the columns are numbered from left to right from 1 to m. We will denote the element on the intersecting of the i-th row and the j-th column as aij.

We'll call submatrix i1, j1, i2, j2 (1 ≤ i1 ≤ i2 ≤ n; 1 ≤ j1 ≤ j2 ≤ m) such elements aij of the given matrix that i1 ≤ i ≤ i2 AND j1 ≤ j ≤ j2. We'll call the area of the submatrix number (i2 - i1 + 1)·(j2 - j1 + 1). We'll call a submatrix inhomogeneous, if all its elements are distinct.

Find the largest (in area) inhomogenous submatrix of the given matrix.

Input

The first line contains two integers n, m (1 ≤ n, m ≤ 400) — the number of rows and columns of the matrix, correspondingly.

Each of the next n lines contains m integers aij (1 ≤ aij ≤ 160000) — the elements of the matrix.

Output

Print a single integer — the area of the optimal inhomogenous submatrix.

Examples

Input

3 3
1 3 1
4 5 6
2 6 1


Output

6


Input

3 4
5 2 3 1
3 3 5 3
4 4 4 5


Output

4


Input

2 6
1 2 3 4 5 6
8 6 7 8 9 1


Output

8

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Random;

public class F {
    
    static void process_cr(int[][] in, int r1, int c1, int r2, int c2, boolean add, HashMap<Integer,Integer> s) {
        for (int c=c1; c<=c2; c++) {
            for (int r=r1; r<=r2; r++) {
                if(add) {
                    s.put(in[r][c], (r<<16)+c);
                } else {
                    s.remove(in[r][c]);
                }
            }
        }
    }
    
    static void process_rc(int[][] in, int r1, int c1, int r2, int c2, boolean add, HashMap<Integer,Integer> s) {
        for (int r=r1; r<=r2; r++) {
            for (int c=c1; c<=c2; c++) {
                if(add) {
                    s.put(in[r][c], (r<<16)+c);
                } else {
                    s.remove(in[r][c]);
                }
            }
        }
    }
    
    static void set_rect(int[][] in, 
            int r1_old, int c1_old, int r2_old, int c2_old,
            int r1_new, int c1_new, int r2_new, int c2_new,
            HashMap<Integer,Integer> s) {
        //delete
        process_cr(in, r1_old, c1_old, r2_old, Math.min(c1_new-1, c2_old), false, s);
        process_cr(in, r1_old, Math.max(c2_new+1, c1_old), r2_old, c2_old, false, s);

        process_rc(in, r1_old, c1_old, Math.min(r1_new-1, r2_old), c2_old, false, s);
        process_rc(in, Math.max(r2_new+1, r1_old), c1_old, r2_old, c2_old, false, s);

        //add
        process_cr(in, r1_new, c1_new, r2_new, Math.min(c1_old-1, c2_new), true, s);
        process_cr(in, r1_new, Math.max(c2_old+1, c1_new), r2_new, c2_new, true, s);
        
        process_rc(in, r1_new, c1_new, Math.min(r1_old-1, r2_new), c2_new, true, s);
        process_rc(in, Math.max(r2_old+1, r1_new), c1_new, r2_new, c2_new, true, s);

        
//        HashMap<Integer,Integer> s2=new HashMap<Integer, Integer>();
//        for (int i=r1_new; i<=r2_new; i++) {
//            for (int j=c1_new; j<=c2_new; j++) {
//                s2.put(in[i][j], (i<<16)+j);
//            }
//        }
//        
//        if(!s.equals(s2)) {
//            throw new IllegalStateException();
//        }
    }
    
    static class two_points {
        short r1,c1,r2,c2;
        
        two_points(int r1, int c1, int r2, int c2) {
            this.r1=(short)r1; this.c1=(short)c1; this.r2=(short)r2; this.c2=(short)c2;
        }
        
        public String toString() {
            return "("+r1+","+c1+")("+r2+","+c2+")";
        }
    }
    
    static int solve2(int[][] in) {
        int n=in.length, m=in[0].length;
        
        HashMap<Integer,Integer> s=new HashMap<Integer,Integer>();
        two_points[][] 
                prev=new two_points[m][n],
                curr=new two_points[m][n]; 
        
        int max=0, r1_old=n, c1_old=m, r2_old=-1, c2_old=-1;
        for (int r=0; r<n; r++) {
            for (int c=0; c<m; c++) {
                for (int h=n-1; h>=r; h--) {
                    
                    if(c>0 && curr[c-1][h].c1>=c) {
                        curr[c][h]=curr[c-1][h];
                    } else if(r>0 && Math.min(prev[c][h].r1, prev[c][h].r2)>=r) {
                        curr[c][h]=prev[c][h];
                    } else if(h+1<n && Math.max(curr[c][h+1].r1, curr[c][h+1].r2)<=h) {
                        curr[c][h]=curr[c][h+1];
                    } else {
                        
                        int right=c-1;
                        if(c>0 && curr[c-1][h].c2-1>right) {
                            right=curr[c-1][h].c2-1;
                        }
                        if(r>0 && prev[c][h].c2-1>right) {
                            right=prev[c][h].c2-1;
                        }
                        if(h+1<n && curr[c][h+1].c2-1>right) {
                            right=curr[c][h+1].c2-1;
                        }
                        
                        set_rect(in, r1_old, c1_old, r2_old, c2_old, r, c, h, right, s);
                        
                        for (int c2=right+1; curr[c][h]==null&&c2<m; c2++) {
                            for (int r2=r; r2<=h; r2++) {
                                Integer v=s.get(in[r2][c2]);
                                if(v!=null) {
                                    int r1=v>>16, c1=(short)v.intValue();
                                    curr[c][h]=new two_points(r1, c1, r2, c2);
                                    if(max<(h-r+1)*(c2-c)) {
                                        max=(h-r+1)*(c2-c);
                                    }
                                    
                                    while (r2>r) {
                                        s.remove(in[--r2][c2]);
                                    }
                                    r1_old=r; c1_old=c; r2_old=h; c2_old=c2-1;
                                    break;
                                } else {
                                    s.put(in[r2][c2], (r2<<16)+c2);
                                }
                            }
                        }
                        
                        if(curr[c][h]==null) {
                            curr[c][h]=new two_points(h, m, h, m);
                            if(max<(h-r+1)*(m-c)) {
                                max=(h-r+1)*(m-c);
                            }
                            r1_old=r; c1_old=c; r2_old=h; c2_old=m-1;
                        }
                    }
                }
            }
            two_points[][] tmp=curr; curr=prev; prev=tmp;
            for (int c=0; c<m; c++) {
                for (int h=0; h<n; h++) {
                    curr[c][h]=null;
                }
            }
        }
        
        return max;
    }
    
    static int solve(int[][] in) {
        int n=in.length, m=in[0].length;
        
        HashMap<Integer,Integer> s=new HashMap<Integer,Integer>();
        two_points[][] 
                prev=new two_points[m][n],
                curr=new two_points[m][n]; 
        
        int max=0;
        for (int r=0; r<n; r++) {
            for (int c=0; c<m; c++) {
                for (int h=n-1; h>=r; h--) {
                    
                    if(c>0 && curr[c-1][h].c1>=c) {
                        curr[c][h]=curr[c-1][h];
                    } else if(r>0 && Math.min(prev[c][h].r1, prev[c][h].r2)>=r) {
                        curr[c][h]=prev[c][h];
                    } else if(h+1<n && Math.max(curr[c][h+1].r1, curr[c][h+1].r2)<=h) {
                        curr[c][h]=curr[c][h+1];
                    } else {
                        
                        s.clear();
                        for (int c2=c; curr[c][h]==null&&c2<m; c2++) {
                            for (int r2=r; r2<=h; r2++) {
                                Integer v=s.get(in[r2][c2]);
                                if(v!=null) {
                                    int r1=v>>16, c1=(short)v.intValue();
                                    curr[c][h]=new two_points(r1, c1, r2, c2);
                                    if(max<(h-r+1)*(c2-c)) {
                                        max=(h-r+1)*(c2-c);
                                    }
                                    break;
                                } else {
                                    s.put(in[r2][c2], (r2<<16)+c2);
                                }
                            }
                        }
                        
                        if(curr[c][h]==null) {
                            curr[c][h]=new two_points(h, m, h, m);
                            if(max<(h-r+1)*(m-c)) {
                                max=(h-r+1)*(m-c);
                            }
                        }
                    }
                }
            }
            two_points[][] tmp=curr; curr=prev; prev=tmp;
            for (int c=0; c<m; c++) {
                for (int h=0; h<n; h++) {
                    curr[c][h]=null;
                }
            }
        }
        
        return max;
    }
    

    
    
    
    static StringBuilder sb=new StringBuilder();
    static void parse(String l, int[] here) {
        sb.setLength(0);
        int len=l.length(), j=0;
        for (int i=0; i<len; i++) {
            char c=l.charAt(i);
            if(c==' ') {
                here[j++]=Integer.parseInt(sb.toString());
                sb.setLength(0);
            } else {
                sb.append(c);
            }
        }
        if(sb.length()>0) {
            here[j++]=Integer.parseInt(sb.toString());
        }
    }
    
    static void run_stream(InputStream ins) throws IOException {
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String[] nm=br.readLine().split(" ");
        int n=Integer.parseInt(nm[0]);
        int m=Integer.parseInt(nm[1]);
        int[][]in=new int[n][m];
        for (int i=0; i<n; i++) {
            parse(br.readLine(), in[i]);
        }
        
        System.out.println(solve2(in));
    }

    public static void main(String[] args) throws IOException {
        run_stream(System.in);
        //run_random(500);
    }

    
    static void run_random(int n) {
        Random r=new Random();
        int[][] in=new int[n][n];
        for (int i=0; i<n; i++) {
            for (int j=0; j<n; j++) {
                in[i][j]=r.nextInt(2000000);
            }
        }
        
        long t0=System.currentTimeMillis();
        System.out.print(/*solve(in)+" , "+*/solve(in));
        System.out.print(":"+(System.currentTimeMillis()-t0)+" ");
        t0=System.currentTimeMillis();
        System.out.print(/*solve(in)+" , "+*/solve2(in));
        System.out.println(":"+(System.currentTimeMillis()-t0));
    }
    
    static boolean check(int[][] in, int r1, int c1, int r2, int c2, HashMap<Integer,Integer> s) {
        s.clear();
        for (int r=r1; r<=r2; r++) {
            for (int c=c1; c<=c2; c++) {
                if(s.containsKey(in[r][c])) {
                    return false;
                }
                s.put(in[r][c], 0);
            }
        }
        return true;
    }
    
    static int baseline(int[][] in) {
        int n=in.length, m=in[0].length;
        HashMap<Integer,Integer> s=new HashMap<Integer, Integer>();
        
        int max=0;
        for (int r1=0; r1<n; r1++) {
            for (int c1=0; c1<m; c1++) {
                for (int r2=r1; r2<n; r2++) {
                    for (int c2=c1; c2<m; c2++) {
                        if(check(in, r1, c1, r2, c2, s)) {
                            if(max<(r2-r1+1)*(c2-c1+1)) {
                                max=(r2-r1+1)*(c2-c1+1);
                                System.out.println("found new max "+max+" at ("+r1+","+c1+")("+r2+","+c2+")");
                            }
                        }
                    }
                }
            }
        }
        return max;
    }
}
