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:
import java.util.*;
import java.io.*;

public class d {
   public static void main(String[] Args) 
      throws Exception
   {
      FS sc = new FS(System.in);
      n = sc.nextInt();
      m = sc.nextInt();
      mask = (1<<m)-1;
      
      long ans = 0;
      long lo = 0;
      long hi = 1;
      vals = new int[n][m];
      maps = new int[n];
      for (int i = 0; i < n; i++)
         for (int j = 0; j < m; j++)
            vals[i][j] = sc.nextInt();
      while (canDo(hi)) {
         ans = hi;
         lo = hi + 1;
         hi = hi * 2;
      }
      while (lo <= hi) {
         long mid = (lo + hi) / 2;
         if (canDo(mid)) {
            ans = mid;
            lo = mid + 1;
         } else {
            hi = mid - 1;
         }
      }
      get(ans);
   }
   public static int[][] vals;
   public static int[] maps;
   public static int n, m, mask;
   public static boolean canDo(long x) {
      boolean[] seen = new boolean[mask+1];
      for (int i = 0; i < n; i++) {
         maps[i] = 0;
         for (int j = 0; j < m; j++){
            maps[i] *= 2;
            if (x <= vals[i][j])
               maps[i]++;
         }
         if (mask == maps[i]) return true;
         if (seen[mask^maps[i]])
            return true;
         if (seen[maps[i]])
            continue;
         for (int j = maps[i]; j != 0; j = ((j-1)&maps[i]))
            seen[j] = true;
      }
      return false;
   }
   public static void get(long x) {
      int[] seen = new int[mask+1];
      for (int i = 0; i < n; i++) {
         maps[i] = 0;
         for (int j = 0; j < m; j++){
            maps[i] *= 2;
            if (x <= vals[i][j])
               maps[i]++;
         }
         if (mask == maps[i]) {
            System.out.println((i+1) + " " +(i+1));
            return;
         }
         if (seen[mask^maps[i]] != 0){
            System.out.println(seen[mask^maps[i]] + " " +(i+1));
            return;
         }
         if (0!=seen[maps[i]])
            continue;
         for (int j = maps[i]; j != 0; j = ((j-1)&maps[i]))
            seen[j] = i + 1;
      }
      return;
   }

   public static int comp(Integer[] arr, int s, int e) {
      int x = 1;
      if (s == e)
         return 0;
      while (x <= arr[e]){
         x = x<<1;
      }
      int div = s;
      x >>= 1;
      while ((arr[div]&x)==0)
         div++;
      for (int i = div; i <= e; i++)
         arr[i] = arr[i] ^ x;
      if (div == s) {
         return comp(arr, s, e);
      }
      int ans = comp(arr, s, div-1);
      int tans = comp(arr,div,e);
      if (tans < ans)
         ans = tans;
      
      return ans ^ x;
   }

   public static long gcd(long a, long b) {
      return (b == 0) ? a : gcd(b, a % b);
   }

   public static class FS {
      StringTokenizer st;
      BufferedReader br;

      FS(InputStream in)
         throws Exception
      {
         br = new BufferedReader(new InputStreamReader(in));
         st = new StringTokenizer(br.readLine());
      }

      String next()
         throws Exception
      {
         if (st.hasMoreTokens())
            return st.nextToken();
         st = new StringTokenizer(br.readLine());
         return next();
      }

      int nextInt()
         throws Exception
      {
         return Integer.parseInt(next());
      }
      long nextLong()
         throws Exception
      {
         return Long.parseLong(next());
      }
   }
}