Problem: You are given n arrays a_1, a_2, ..., a_n; each array consists of exactly m integers. We denote the y-th element of the x-th array as a_{x, y}.

You have to choose two arrays a_i and a_j (1 ≤ i, j ≤ n, it is possible that i = j). After that, you will obtain a new array b consisting of m integers, such that for every k ∈ [1, m] b_k = max(a_{i, k}, a_{j, k}).

Your goal is to choose i and j so that the value of min _{k = 1}^{m} b_k is maximum possible.

Input

The first line contains two integers n and m (1 ≤ n ≤ 3 ⋅ 10^5, 1 ≤ m ≤ 8) — the number of arrays and the number of elements in each array, respectively.

Then n lines follow, the x-th line contains the array a_x represented by m integers a_{x, 1}, a_{x, 2}, ..., a_{x, m} (0 ≤ a_{x, y} ≤ 10^9).

Output

Print two integers i and j (1 ≤ i, j ≤ n, it is possible that i = j) — the indices of the two arrays you have to choose so that the value of min _{k = 1}^{m} b_k is maximum possible. If there are multiple answers, print any of them.

Example

Input


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


Output


1 5

Solution (in JAVA):

Solution:
//package codeforces.educational80;

import java.io.*;
import java.util.*;

public class MinimaxProblem {
    private static int UNVISITED = 0;
    private static int VISITING = -1;
    private static int VISITED = 1;

    public static void main(String[] args) {
//        try {
//            FastScanner in = new FastScanner(new FileInputStream("src/input.in"));
//            PrintWriter out = new PrintWriter(new FileOutputStream("src/output.out"));

        FastScanner in = new FastScanner(System.in);
        PrintWriter out = new PrintWriter(System.out);

            solve(1, in ,out);

//        } catch (IOException e) {
//            e.printStackTrace();
//        }
    }

    private static void solve(int q, FastScanner in, PrintWriter out) {
        for (int qq = 0; qq < q; qq++) {
            int n = in.nextInt(), m = in.nextInt();
            int[][] a = new int[n][m];
            int l = 0, r = 0, singleMax = -1, singleIdx = -1;
            for(int i = 0; i < n; i++) {
                int currMin = (int)1e9 + 1;
                for(int j = 0; j < m; j++) {
                    a[i][j] = in.nextInt();
                    r = Math.max(r, a[i][j]);
                    currMin = Math.min(currMin, a[i][j]);
                }
                if(currMin > singleMax) {
                    singleMax = currMin;
                    singleIdx = i;
                }
            }

            while(l < r - 1) {
                int mid = l + (r - l) / 2;
                if(binarySearch(a, mid, m)[0] >= 0) {
                    l = mid;
                }
                else {
                    r = mid - 1;
                }
            }

            if(r <= singleMax) {
                //out.println(singleMax);
                out.print((singleIdx + 1) + " " + (singleIdx + 1));
            }
            else {
                int[] dr = binarySearch(a, r, m);
                if(dr[0] >= 0) {
                    //out.println(r);
                    out.print((dr[0] + 1) + " " + (dr[1] + 1));
                }
                else {
                    int[] dl = binarySearch(a, l, m);
                    if(dl[0] >= 0 && l > singleMax) {
                        //out.println(l);
                        out.print((dl[0] + 1) + " " + (dl[1] + 1));
                    }
                    else {
                        //out.println(singleMax);
                        out.print((singleIdx + 1) + " " + (singleIdx + 1));
                    }
                }
            }
        }
        out.close();
    }

    private static int[] binarySearch(int[][] a, int x, int m) {
        int[] res = new int[2];
        Arrays.fill(res, -1);
        int bitMaskCnt = (int)Math.pow(2, m);
        List<Integer>[] bmList = new List[bitMaskCnt];
        for(int i = 0; i < bitMaskCnt; i++) {
            bmList[i] = new ArrayList<>();
        }
        for(int i = 0; i < a.length; i++) {
            int mask = 0;
            for(int j = 0; j < m; j++) {
                if(a[i][j] >= x) {
                    mask |= (1 << j);
                }
            }
            bmList[mask].add(i);
        }

        if(bmList[bitMaskCnt - 1].size() > 0) {
            res[0] = bmList[bitMaskCnt - 1].get(0);
            res[1] = bmList[bitMaskCnt - 1].get(0);
        }
        for(int i = 1; i <= bitMaskCnt - 2; i++) {
            if(bmList[i].size() > 0) {
                for(int j = i + 1; j <= bitMaskCnt - 2; j++) {
                    if((i | j) == bitMaskCnt - 1 && bmList[j].size() > 0) {
                        res[0] = bmList[i].get(0);
                        res[1] = bmList[j].get(0);
                        break;
                    }
                }
            }
        }
        return res;
    }
    private static long modularAdd(long a, long b, int mod) {
        long sum = a + b;
        if (sum >= mod) {
            sum -= mod;
        }
        return sum;
    }

    private static long modularSubtract(long a, long b, int mod) {
        long diff = a - b;
        if (diff < 0) {
            diff += mod;
        }
        return diff;
    }

    private static Stack<Integer> topologicalSort(Set<Integer>[] g) {
        Stack<Integer> stack = new Stack<>();
        int[] state = new int[g.length];

        for (int node = 0; node < g.length; node++) {
            if (!topoSortHelper(g, stack, state, node)) {
                return null;
            }
        }
        return stack;
    }

    private static boolean topoSortHelper(Set<Integer>[] g, Stack<Integer> stack, int[] state, int currNode) {
        if (state[currNode] == VISITED) {
            return true;
        } else if (state[currNode] == VISITING) {
            return false;
        }
        state[currNode] = VISITING;
        for (int neighbor : g[currNode]) {
            if (!topoSortHelper(g, stack, state, neighbor)) {
                return false;
            }
        }
        state[currNode] = VISITED;
        stack.push(currNode);
        return true;
    }

    static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        FastScanner(InputStream stream) {
            try {
                br = new BufferedReader(new InputStreamReader(stream));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        String nextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }
    }
}