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

/**
 *
 * @author Saju
 *
 */

public class Main {

	private static int dx[] = { 1, 0, -1, 0 };
	private static int dy[] = { 0, -1, 0, 1 };

	private static final long INF = Long.MAX_VALUE;
	private static final int INT_INF = Integer.MAX_VALUE;
	private static final long NEG_INF = Long.MIN_VALUE;
	private static final int NEG_INT_INF = Integer.MIN_VALUE;
	private static final double EPSILON = 1e-10;

	private static final int MAX = 1007;
	private static final long MOD = 1000000007;

	private static final int MAXN = 100007;
	private static final int MAXA = 10000009;
	private static final int MAXLOG = 22;

	public static void main(String[] args) {

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

/*

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


*/
		
		
		int n = in.nextInt();
        int m = in.nextInt();
 
        int[][] arr = new int[n][m];
 
        for (int i = 0; i < n; i++) {
        	 for (int j = 0; j < m; j++) {
                 arr[i][j] = in.nextInt();	
        	 }
        }
           
 
 
        int[] maxIndex = new int[1 << m];
        int[] maxValue = new int[1 << m];
        
 
        for (int i = 1; i < 1 << m; i++)
        {
            int max = -1;
            int maxi = -1;
 
            for (int j = 0; j < n; j++)
            {
                int min = Integer.MAX_VALUE;
 
                for (int k = 0; k < m; k++) {
                	 if ((i & (1 << k)) != 0) {
//                		 System.out.println(i + " " + j + " " + k);
                		 min = Math.min(min, arr[j][k]);
                	 }
                }
                   
 
                if (min > max)
                {
                    max = min;
                    maxi = j;
                }
            }
 
//            System.out.println("max: " + maxIndex + " " + max);
            maxIndex[i] = maxi;
            maxValue[i] = max;
        }
 
//        System.out.println(Arrays.toString(maxIndex));
//        System.out.println(Arrays.toString(maxValue));
		
        
        int index1 = -1;
        int index2 = -1;
        int max = -1 ;
        for (int i = 1, j = (1 << m) - 2; i < 1 << m; j--, i++)
        {
        	
            int val = Math.min(maxValue[i], maxValue[j]);
 
            if (val > max)
            {
//            	System.out.println(i);
                max = val;
                index1 = maxIndex[i];
                index2 = maxIndex[j];
            }
        }
 
        out.println((index1 + 1) + " " + (index2 + 1));
        
		out.flush();
		out.close();
		System.exit(0);
	}

	

	private static long ceil(long d, long div) {
		if(d % div == 0) {
			return d / div;
		}
		return (d + div) / div;
	}



	private static boolean isPalindrome(String str) {
		StringBuilder sb = new StringBuilder();
		sb.append(str);
		String str1 = sb.reverse().toString();
		return str.equals(str1);
	}

	private static String reverseString(String str) {
		StringBuilder sb = new StringBuilder();
		sb.append(str);
		return sb.reverse().toString();
	}

	private static double distance(Point p1, Point p2) {
		long divx = p2.x - p1.x;
		long divy = p2.y - p1.y;
		divx = divx * divx;
		divy = divy * divy;
		return Math.sqrt(divx + divy);
	}

	private static String getBinaryStr(int n, int j) {
		String str = Integer.toBinaryString(n);
		int k = str.length();
		for (int i = 1; i <= j - k; i++) {
			str = "0" + str;
		}

		return str;
	}

	// O(log(max(A,M)))
	static long modInverse(long a, long m) {
		extendedEuclid(a, m);
		return (x % m + m) % m;
	}

	static long x;
	static long y;
	static long gcdx;

	private static void extendedEuclid(long a, long b) {
		if (b == 0) {
			gcdx = a;
			x = 1;
			y = 0;
		} else {
			extendedEuclid(b, a % b);
			long temp = x;
			x = y;
			y = temp - ((a / b) * y);
		}
	}

	private static void generatePrime(int n) {
		// O(NloglogN)
		boolean arr[] = new boolean[n + 5];
		Arrays.fill(arr, true);
		for (int i = 2; i * i <= n; i++) {
			if (arr[i] == true) {
				for (int j = i * i; j <= n; j += i) {
					arr[j] = false;
				}
			}
		}
		int count = 0;
		int start = 0;
		for (int i = 2; i <= n; i++) {
			if (arr[i] == true) {
				// System.out.println(i + " ");
				count++;
			}
			if (count == (start * 100) + 1) {
				// System.out.println(i);
				start++;
			}
		}
		System.out.println();
		System.out.println(count);

	}

	private static Map<Long, Long> primeFactorization(long n, long m) {
		Map<Long, Long> map = new HashMap<>();

		for (long i = 2; i <= Math.sqrt(n); i++) {
			if (n % i == 0) {
				long count = 0;
				while (n % i == 0) {
					count++;
					n = n / i;
				}
				long val = count * m;
				map.put(i, val);
				// System.out.println("i: " + i + ", count: " + count);
			}

		}
		if (n != 1) {
			// System.out.println(n);
			map.put(n, m);
		}
		return map;
	}

	private static class Point {
		long x;
		long y;

		Point(long x, long y) {
			this.x = x;
			this.y = y;
		}

		@Override
		public boolean equals(Object obj) {
			Point ob = (Point) obj;
			if (this.x == ob.x && this.y == ob.y) {
				return true;
			}
			return false;

		}

		@Override
		public String toString() {
			return this.x + " " + this.y;
		}

		@Override
		public int hashCode() {
			return 0;
		}
	}

	private static long pow(int base, int pow) {
		long val = 1L;
		for (int i = 1; i <= pow; i++) {
			val *= base;
		}
		return val;
	}

	private static int log(int x, int base) {
		return (int) (Math.log(x) / Math.log(base));
	}

	private static int log(long x, int base) {
		return (int) (Math.log(x) / Math.log(base));
	}

	private static long max(long a, long b) {
		if (a >= b) {
			return a;
		}
		return b;
	}

	private static long abs(long a) {
		if (a < 0) {
			return -a;
		}
		return a;
	}

	private static int abs(int a) {
		if (a < 0) {
			return -a;
		}
		return a;
	}

	private static int max(int a, int b) {
		if (a >= b) {
			return a;
		}
		return b;
	}

	private static int min(int a, int b) {
		if (a <= b) {
			return a;
		}
		return b;
	}

	private static long min(long a, long b) {
		if (a <= b) {
			return a;
		}
		return b;
	}

	private static long gcd(long a, long b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	private static int gcd(int a, int b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	private static long bigMod(long n, long k, long m) {

		long ans = 1;
		while (k > 0) {
			if ((k & 1) == 1) {
				ans = (ans * n) % m;
			}
			n = (n * n) % m;
			k >>= 1;
		}
		return ans;
	}

	/*
	 * Returns an iterator pointing to the first element in the range [first, last]
	 * which does not compare less than val.
	 * 
	 */
	private static int lowerBoundNew(long[] arr, long num) {
		int start = 0;
		int end = arr.length - 1;
		int index = 0;
		int len = arr.length;
		int mid = 0;
		while (true) {
			if (start > end) {
				break;
			}
			mid = (start + end) / 2;
			if (arr[mid] > num) {
				end = mid - 1;
			} else if (arr[mid] < num) {
				start = mid + 1;
			} else {
				while (mid >= 0 && arr[mid] == num) {
					mid--;
				}
				return mid + 1;
			}
		}
		if (arr[mid] < num) {
			return mid + 1;
		}
		return mid;
	}

	/*
	 * upper_bound() is a standard library function in C++ defined in the header .
	 * It returns an iterator pointing to the first element in the range [first,
	 * last) that is greater than value, or last if no such element is found
	 * 
	 */
	private static int upperBoundNew(long arr[], long num) {

		int start = 0;
		int end = arr.length - 1;
		int index = 0;
		int len = arr.length;
		int mid = 0;
		while (true) {
			if (start > end) {
				break;
			}
			mid = (start + end) / 2;
			long val = arr[mid];
			if (val > num) {
				end = mid - 1;
			} else if (val < num) {
				start = mid + 1;
			} else {
				while (mid < len && arr[mid] == num) {
					mid++;
				}
				if (mid == len - 1 && arr[mid] == num) {
					return mid + 1;
				} else {
					return mid;
				}
			}
		}
		if (arr[mid] < num) {
			return mid + 1;
		}
		return mid;
	}

	private static class InputReader {
		public BufferedReader reader;
		public StringTokenizer tokenizer;

		public InputReader(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream));
			tokenizer = null;
		}

		public String next() {
			try {
				while (tokenizer == null || !tokenizer.hasMoreTokens()) {
					tokenizer = new StringTokenizer(reader.readLine());

				}
			} catch (IOException e) {
				return null;
			}
			return tokenizer.nextToken();
		}

		public String nextLine() {
			String line = null;
			try {
				tokenizer = null;
				line = reader.readLine();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			return line;
		}

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

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

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

		public boolean hasNext() {
			try {
				while (tokenizer == null || !tokenizer.hasMoreTokens()) {
					tokenizer = new StringTokenizer(reader.readLine());
				}
			} catch (Exception e) {
				return false;
			}
			return true;
		}
	}
}