import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.BufferedWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.Comparator;
import java.util.Collections;
import java.io.InputStream;

/**
 * Built using CHelper plug-in Actual solution is at the top
 *
 * @author ilyakor
 */
public class Main {

  public static void main(String[] args) {
    InputStream inputStream = System.in;
    OutputStream outputStream = System.out;
    InputReader in = new InputReader(inputStream);
    OutputWriter out = new OutputWriter(outputStream);
    TaskE1 solver = new TaskE1();
    int testCount = Integer.parseInt(in.next());
    for (int i = 1; i <= testCount; i++) {
      solver.solve(i, in, out);
    }
    out.close();
  }

  static class TaskE1 {

    public void solve(int testNumber, InputReader in, OutputWriter out) {
      int n = in.nextInt();
      int m = in.nextInt();
      // int n = 12;
      // int m = 2000;
      int[][] d = new int[2][1 << n];
      int[] buf = new int[1 << n];
      int[][] a = new int[m][n];
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
          a[j][i] = in.nextInt();
          // a[j][i] = (int)((i * 12346L + j * 789L) % 100000);
        }
      }

      ArrayList<Integer> inds = new ArrayList<>();
      for (int i = 0; i < m; ++i) {
        inds.add(i);
      }
      int[][] finalA = a;
      Collections.sort(inds, new Comparator<Integer>() {

        public int compare(Integer i1, Integer i2) {
          int val1 = 0, val2 = 0;
          for (int i = 0; i < n; ++i) {
            if (finalA[i1][i] > val1) {
              val1 = finalA[i1][i];
            }
          }
          for (int i = 0; i < n; ++i) {
            if (finalA[i2][i] > val2) {
              val2 = finalA[i2][i];
            }
          }
          return -Integer.compare(val1, val2);
        }
      });
      int newM = Math.min(m, n + 1);
      int[][] na = new int[newM][];
      for (int i = 0; i < newM; ++i) {
        int ind = inds.get(i);
        na[i] = a[ind];
      }
      m = newM;
      a = na;

      for (int i = 0; i < m; ++i) {
        int[] prev = d[i % 2], nx = d[(i + 1) % 2];
        for (int shift = 0; shift < n; ++shift) {
          int[] b = new int[n];
          for (int j = 0; j < n; ++j) {
            b[j] = a[i][(j + shift) % n];
          }
          System.arraycopy(prev, 0, buf, 0, prev.length);
          for (int j = 0; j < n; ++j) {
            int inc = b[j];
            for (int mask = 0; mask < (1 << n); ++mask) {
              if ((mask >> j) % 2 == 0) {
                int val = buf[mask] + inc;
                int nm = mask ^ (1 << j);
                if (val > buf[nm]) {
                  buf[nm] = val;
                }
              }
            }
          }
          for (int mask = 0; mask < (1 << n); ++mask) {
            if (nx[mask] < buf[mask]) {
              nx[mask] = buf[mask];
            }
          }
        }
      }
      out.printLine(d[m % 2][(1 << n) - 1]);
    }

  }

  static class OutputWriter {

    private final PrintWriter writer;

    public OutputWriter(OutputStream outputStream) {
      writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
    }

    public OutputWriter(Writer writer) {
      this.writer = new PrintWriter(writer);
    }

    public void print(Object... objects) {
      for (int i = 0; i < objects.length; i++) {
        if (i != 0) {
          writer.print(' ');
        }
        writer.print(objects[i]);
      }
    }

    public void printLine(Object... objects) {
      print(objects);
      writer.println();
    }

    public void close() {
      writer.close();
    }

  }

  static class InputReader {

    private InputStream stream;
    private byte[] buffer = new byte[10000];
    private int cur;
    private int count;

    public InputReader(InputStream stream) {
      this.stream = stream;
    }

    public static boolean isSpace(int c) {
      return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

    public int read() {
      if (count == -1) {
        throw new InputMismatchException();
      }
      try {
        if (cur >= count) {
          cur = 0;
          count = stream.read(buffer);
          if (count <= 0) {
            return -1;
          }
        }
      } catch (IOException e) {
        throw new InputMismatchException();
      }
      return buffer[cur++];
    }

    public int readSkipSpace() {
      int c;
      do {
        c = read();
      } while (isSpace(c));
      return c;
    }

    public String nextToken() {
      int c = readSkipSpace();
      StringBuilder sb = new StringBuilder();
      while (!isSpace(c)) {
        sb.append((char) c);
        c = read();
      }
      return sb.toString();
    }

    public String next() {
      return nextToken();
    }

    public int nextInt() {
      int sgn = 1;
      int c = readSkipSpace();
      if (c == '-') {
        sgn = -1;
        c = read();
      }
      int res = 0;
      do {
        if (c < '0' || c > '9') {
          throw new InputMismatchException();
        }
        res = res * 10 + c - '0';
        c = read();
      } while (!isSpace(c));
      res *= sgn;
      return res;
    }

  }
}


/*input
3
2 3
2 5 7
4 2 4
3 6
4 1 5 2 10 4
8 6 6 4 9 10
5 4 9 5 8 7
3 3
9 9 9
1 1 1
1 1 1

*/
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.PrintStream;
import java.util.StringTokenizer;
import java.util.Random;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.util.*;

public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		int T = in.nextInt();
		for (int cT = 1; cT <= T; cT++) {
			Task solver = new Task();
			solver.solve(cT, in, out);
		}
		out.close();
	}

	static class data {
		int val, col;
		data(int _val, int _col) {
			val = _val; col = _col;
		}

		@Override
		public String toString() {
			return String.format("(%d,%d)", val, col);
		}
	}

	static class Task {
		int[][] a;
		int[][] b;
		int[][] dp;
		int[][] mb;

		ArrayList<data> all = new ArrayList<>();
		Set<Integer> st = new HashSet<>();
		int n, m;

		int cal(int col, int mask) {
			if (col == m) {
				if (Integer.bitCount(mask) == n) return 0;
				return (int)(-1e9);
			}
			int ret = dp[col][mask];
			if (ret != -1) return ret;
			int rmask = mask ^ ((1 << n) - 1);
			// ret is not a reference
			for (int mask2 = rmask; mask2 > 0; mask2 = rmask & (mask2 - 1)) {
				int now = cal(col + 1, mask | mask2) + mb[col][mask2];
				ret = Math.max(ret, now);
			}
			ret = Math.max(ret, cal(col + 1, mask));
			dp[col][mask] = ret;
			return ret;
		}
		public static int fsb(int n) {
			return (int)((Math.log10(n & -n)) / Math.log10(2)) + 1;
		}

		void prepMb() {
			// col, cyclic, mask
			for (int col = 0; col < m; col++) {
				for (int mask = 1; mask < (1 << n); mask++) {
					int nmask = mask;
					while ((nmask & 1) == 0) nmask >>= 1;
					if (nmask == mask) {
						for (int shift = 0; shift < n; shift++) {
							int sum = 0;
							int tmask = mask;
							while (tmask > 0) {
								int i = Integer.numberOfTrailingZeros(tmask);
								sum += b[(i + shift) % n][col]; tmask ^= (1 << i);
							}
							mb[col][mask] = Math.max(mb[col][mask], sum);
						}
					} else {
						mb[col][mask] = mb[col][nmask];
					}
				}
			}
		}

		void solve(int testNumber, InputReader in, PrintWriter out) {
			n = in.nextInt(); m = in.nextInt();
			a = new int[n][m];
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					a[i][j] = in.nextInt();
					all.add(new data(a[i][j], j));
				}
			}
			Collections.sort(all, new Comparator<data>() {
				@Override
				public int compare(final data o1, final data o2) {
					return -(o1.val - o2.val);
				}
			});
			for (data it : all) {
				if (st.size() == n) break;
				st.add(it.col);
			}
			b = new int[n][st.size()];
			int rcol = 0;
			for (int col : st) {
				for (int row = 0; row < n; row++)
					b[row][rcol] = a[row][col];
				rcol++;
			}
			m = st.size();
			dp = new int[n][(1 << n)];
			mb = new int[m][(1 << n)];

			prepMb();
			for (int i = 0; i < n; i++)
				Arrays.fill(dp[i], -1);
			System.out.println(cal(0, 0));
		}
	}

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

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

		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

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

	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.FilterInputStream;
import java.io.BufferedInputStream;
import java.util.Random;
import java.util.Comparator;
import java.io.InputStream;

/**
 * @author khokharnikunj8
 */

public class Main {
    public static void main(String[] args) {
        new Thread(null, new Runnable() {
            public void run() {
                new Main().solve();
            }
        }, "1", 1 << 26).start();
    }

    void solve() {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        ScanReader in = new ScanReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2RotateColumnsHardVersion solver = new E2RotateColumnsHardVersion();
        int testCount = in.scanInt();
        for (int i = 1; i <= testCount; i++)
            solver.solve(i, in, out);
        out.close();
    }

    static class E2RotateColumnsHardVersion {
        int[][] dp;
        int[] cur;

        public void solve(int testNumber, ScanReader in, PrintWriter out) {
            int n = in.scanInt();
            int m = in.scanInt();
            int[][] ar = new int[n][m];
            int[][] max = new int[m][2];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) ar[i][j] = in.scanInt();
            }

            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    max[i][0] = Math.max(max[i][0], ar[j][i]);
                }
                max[i][1] = i;
            }
            CodeHash.shuffle(max);
            Arrays.sort(max, new Comparator<int[]>() {

                public int compare(int[] o1, int[] o2) {
                    return -o1[0] + o2[0];
                }
            });
            dp = new int[2][1 << n];
            cur = new int[1 << n];
            for (int i = 0; i < Math.min(m, n); i++) {
                Arrays.fill(cur, 0);
                Arrays.fill(dp[i & 1], 0);
                for (int j = 0; j < 1 << n; j++) {
                    for (int k = 0; k < n; k++) {
                        int sum = 0;
                        for (int l = 0; l < n; l++) {
                            if ((j & (1 << l)) != 0) {
                                sum += (ar[(k + l) % n][max[i][1]]);
                            }
                        }
                        cur[j] = Math.max(cur[j], sum);
                    }
                }
                for (int j = 0; j < (1 << n); j++) {
                    for (int k = j; ; k = (k - 1) & j) {
                        dp[i & 1][j] = Math.max(dp[i & 1][j], dp[(i - 1) & 1][k] + cur[j ^ k]);
                        if (k == 0) break;
                    }
                }
            }
            out.println(dp[Math.min(n, m) & 1 ^ 1][(1 << n) - 1]);
        }

    }

    static class CodeHash {
        public static void shuffle(int[][] ar) {
            Random rd = new Random(new Random().nextInt());
            for (int i = 0; i < ar.length; i++) {
                int index = rd.nextInt(ar.length);
                int[] temp = ar[i];
                ar[i] = ar[index];
                ar[index] = temp;
            }
        }

    }

    static class ScanReader {
        private byte[] buf = new byte[4 * 1024];
        private int index;
        private BufferedInputStream in;
        private int total;

        public ScanReader(InputStream inputStream) {
            in = new BufferedInputStream(inputStream);
        }

        private int scan() {
            if (index >= total) {
                index = 0;
                try {
                    total = in.read(buf);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (total <= 0) return -1;
            }
            return buf[index++];
        }

        public int scanInt() {
            int integer = 0;
            int n = scan();
            while (isWhiteSpace(n)) n = scan();
            int neg = 1;
            if (n == '-') {
                neg = -1;
                n = scan();
            }
            while (!isWhiteSpace(n)) {
                if (n >= '0' && n <= '9') {
                    integer *= 10;
                    integer += n - '0';
                    n = scan();
                }
            }
            return neg * integer;
        }

        private boolean isWhiteSpace(int n) {
            if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
            else return false;
        }

    }
}


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

public class Main {
	public static void main(String args[]) {new Main().run();}

	FastReader in = new FastReader();
	PrintWriter out = new PrintWriter(System.out);
	void run(){
		int t=in.nextInt();
		for(int i=0;i<t;i++) {
			out.println(work());
		}
		out.flush();
	}
	long mod=1000000007;
	long gcd(long a,long b) {
		return b==0?a:gcd(b,a%b);
	}
	int work() {
		int n=in.nextInt();
		int m=in.nextInt();
		int[][] A=new int[n][m];
		int[][] B=new int[n][m];
		int[][] R=new int[m][2];
		for(int i=0;i<m;i++)R[i][1]=i;
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				A[i][j]=in.nextInt();
				R[j][0]=Math.max(R[j][0], A[i][j]);
			}
		}
		Arrays.sort(R,new Comparator<int[]>() {
			public int compare(int[] arr1,int[] arr2) {
				return arr2[0]-arr1[0];
			}
		});
		for(int j=0;j<m;j++) {
			int index=R[j][1];
			for(int i=0;i<n;i++) {
				B[i][j]=A[i][index];
			}
		}
		m=Math.min(n, m);
		int[][] dp=new int[m][1<<n];
		int[][] rec=new int[m][1<<n];
		for(int j=0;j<m;j++) {
			for(int s=0;s<n;s++) {//转
				for(int i=1;i<1<<n;i++) {
					int sum=0;
					for(int b=0;b<n;b++) {
						if(((1<<b)&i)>0) {
							sum+=B[(b+s)%n][j];
						}
					}
					rec[j][i]=Math.max(sum, rec[j][i]);
				}
			}
		}

		for(int j=0;j<m;j++) {
			for(int i=0;i<1<<n;i++) {
				if(j==0) {
					dp[j][i]=rec[j][i];
				}else {
					for(int p=i;p<1<<n;p++) {
						p=p|i;
						dp[j][p]=Math.max(dp[j][p], rec[j][i]+dp[j-1][p^i]);
					}
				}
			}
		}
		return dp[m-1][(1<<n)-1];
	}
}

class FastReader
{
	BufferedReader br;
	StringTokenizer st;

	public FastReader()
	{
		br=new BufferedReader(new InputStreamReader(System.in));
	}

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

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

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


/**
 * BaZ :D
 */
import java.util.*;
import java.io.*;
import static java.lang.Math.*;

public class Main
{
    static MyScanner scan;
    static PrintWriter pw;
    static long MOD = 1_000_000_007;
    static long INF = 1_000_000_000_000_000_000L;
    static long inf = 2_000_000_000;
    public static void main(String[] args) {
        new Thread(null, null, "BaZ", 1 << 27) {
            public void run() {
                try {
                    solve();
                } catch (Exception e) {
                    e.printStackTrace();
                    System.exit(1);
                }
            }
        }.start();
    }
    static int n,m,need,a[][],dp[][][],real[][];
    static void solve() throws IOException
    {
        //initIo(true);
        initIo(false);
        StringBuilder sb = new StringBuilder();
        int t = ni();
        while(t-->0) {
            n = ni();
            m = ni();
            a = new int[n][m];
            for(int i=0;i<n;++i) {
                for(int j=0;j<m;++j) {
                    a[i][j] = ni();
                }
            }
            need = min(n,m);
            Pair max_in_cols[] = new Pair[m];
            for(int COL=0;COL<m;++COL) {
                int max = 0;
                for(int i=0;i<n;++i) {
                    max = max(max, a[i][COL]);
                }
                max_in_cols[COL] = new Pair(max, COL);
            }
            real = new int[n][need];
            Arrays.sort(max_in_cols);
            for(int i=0;i<need;++i) {
                int COL = max_in_cols[m-1-i].y;
                for(int j=0;j<n;++j) {
                    real[j][i] = a[j][COL];
                }
            }
//            pl("need : "+need);
//            pa("Real", real);
            dp = new int[need][n+1][(1<<n)];
            for(int i=0;i<need;++i) {
                for(int j=0;j<=n;++j) {
                    for(int k=0;k<(1<<n);++k) {
                        dp[i][j][k] = -1;
                    }
                }
            }
            pl(f(0, n, 0));
        }
        pw.flush();
        pw.close();
    }
    static int f(int idx, int bias, int mask) {
        //pl("idx: "+idx+" bias : "+bias + " mask : "+mask);
        if(idx==need) {
            return 0;
        }
        if(dp[idx][bias][mask]!=-1) {
            return dp[idx][bias][mask];
        }

        //didn't fix bias yet
        if(bias==n) {
            int max = 0;
            for(int b=0;b<n;++b) {
                max = max(max, f(idx, b, mask));
            }
            //pl("maxxxxxxx : "+max);
            dp[idx][bias][mask] = max;
            return max;
        }
        else {
            int max = f(idx+1, n, mask);
            for(int i=0;i<n;++i) {
                if((mask&(1<<i))==0) {
                    max = max(max, real[(i-bias+n)%n][idx] + f(idx, bias, mask | (1<<i)));
                }
            }
            //pl("max : "+max);
            dp[idx][bias][mask] = max;
            return max;
        }
    }
    static class Pair implements Comparable<Pair>
    {
        int x,y;
        Pair(int x,int y)
        {
            this.x=x;
            this.y=y;
        }
        public int compareTo(Pair other)
        {
            if(this.x!=other.x)
                return this.x-other.x;
            return this.y-other.y;
        }
        public String toString()
        {
            return "("+x+","+y+")";
        }
    }
    static void initIo(boolean isFileIO) throws IOException {
        scan = new MyScanner(isFileIO);
        if(isFileIO) {
            pw = new PrintWriter("/Users/amandeep/Desktop/output.txt");
        }
        else {
            pw = new PrintWriter(System.out, true);
        }
    }
    static int ni() throws IOException
    {
        return scan.nextInt();
    }
    static long nl() throws IOException
    {
        return scan.nextLong();
    }
    static double nd() throws IOException
    {
        return scan.nextDouble();
    }
    static String ne() throws IOException
    {
        return scan.next();
    }
    static String nel() throws IOException
    {
        return scan.nextLine();
    }
    static void pl()
    {
        pw.println();
    }
    static void p(Object o)
    {
        pw.print(o+" ");
    }
    static void pl(Object o)
    {
        pw.println(o);
    }
    static void psb(StringBuilder sb)
    {
        pw.print(sb);
    }
    static void pa(String arrayName, Object arr[])
    {
        pl(arrayName+" : ");
        for(Object o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, int arr[])
    {
        pl(arrayName+" : ");
        for(int o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, long arr[])
    {
        pl(arrayName+" : ");
        for(long o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, double arr[])
    {
        pl(arrayName+" : ");
        for(double o : arr)
            p(o);
        pl();
    }
    static void pa(String arrayName, char arr[])
    {
        pl(arrayName+" : ");
        for(char o : arr)
            p(o);
        pl();
    }
    static void pa(String listName, List list)
    {
        pl(listName+" : ");
        for(Object o : list)
            p(o);
        pl();
    }
    static void pa(String arrayName, Object[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(Object o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, int[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(int o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, long[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(long o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, char[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(char o : arr[i])
                p(o);
            pl();
        }
    }
    static void pa(String arrayName, double[][] arr) {
        pl(arrayName+" : ");
        for(int i=0;i<arr.length;++i) {
            for(double o : arr[i])
                p(o);
            pl();
        }
    }
    static class MyScanner
    {
        BufferedReader br;
        StringTokenizer st;
        MyScanner(boolean readingFromFile) throws IOException
        {
            if(readingFromFile) {
                br = new BufferedReader(new FileReader("/Users/amandeep/Desktop/input.txt"));
            }
            else {
                br = new BufferedReader(new InputStreamReader(System.in));
            }
        }
        String nextLine()throws IOException
        {
            return br.readLine();
        }
        String next() throws IOException
        {
            if(st==null || !st.hasMoreTokens())
                st = new StringTokenizer(br.readLine());
            return st.nextToken();
        }
        int nextInt() throws IOException
        {
            return Integer.parseInt(next());
        }
        long nextLong() throws IOException
        {
            return Long.parseLong(next());
        }
        double nextDouble() throws IOException
        {
            return Double.parseDouble(next());
        }
    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastScanner in = new FastScanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE2 solver = new TaskE2();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE2 {
        public void solve(int testNumber, FastScanner in, PrintWriter out) {
            int numTests = in.nextInt();
            for (int test = 0; test < numTests; test++) {
                int n = in.nextInt();
                int m = in.nextInt();
                int[][] a = new int[n][m];
                for (int i = 0; i < n; i++) {
                    for (int j = 0; j < m; j++) {
                        a[i][j] = in.nextInt();
                    }
                }

                if (m > n) {
                    int[] maxInColumn = new int[m];
                    for (int j = 0; j < m; j++) {
                        for (int i = 0; i < n; i++) {
                            maxInColumn[j] = Math.max(maxInColumn[j], a[i][j]);
                        }
                    }
                    Integer[] cols = new Integer[m];
                    for (int i = 0; i < m; i++) {
                        cols[i] = i;
                    }
                    Arrays.sort(cols, (u, v) -> -(maxInColumn[u] - maxInColumn[v]));

                    int[][] na = new int[n][n];
                    for (int i = 0; i < n; i++) {
                        for (int j = 0; j < n; j++) {
                            na[i][j] = a[i][cols[j]];
                        }
                    }
                    m = n;
                    a = na;
                }

                int[] buf = new int[n];
                int[][] sums = new int[m][1 << n];
                int[] sumsCur = new int[1 << n];
                for (int j = 0; j < m; j++) {
                    for (int shift = 0; shift < n; shift++) {
                        for (int i = 0; i < n; i++) {
                            buf[i] = a[(i + shift) % n][j];
                        }
                        for (int mask = 1; mask < 1 << n; mask++) {
                            int k = Integer.numberOfTrailingZeros(mask);
                            sumsCur[mask] = sumsCur[mask ^ (1 << k)] + buf[k];
                            sums[j][mask] = Math.max(sums[j][mask], sumsCur[mask]);
                        }
                    }
                }

                int[] d = new int[1 << n];
                for (int j = 0; j < m; j++) {
                    for (int mask = (1 << n) - 1; mask >= 0; mask--) {
                        for (int submask = mask; submask > 0; submask = (submask - 1) & mask) {
                            d[mask] = Math.max(d[mask], d[mask ^ submask] + sums[j][submask]);
                        }
                    }
                }
                int ans = 0;
                for (int x : d) {
                    ans = Math.max(ans, x);
                }
                out.println(ans);
            }
        }

    }

    static class FastScanner {
        private BufferedReader in;
        private StringTokenizer st;

        public FastScanner(InputStream stream) {
            in = new BufferedReader(new InputStreamReader(stream));
        }

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

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

    }
}


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastReader in = new FastReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2RotateColumnsHardVersion solver = new E2RotateColumnsHardVersion();
        int testCount = Integer.parseInt(in.next());
        for (int i = 1; i <= testCount; i++)
            solver.solve(i, in, out);
        out.close();
    }

    static class E2RotateColumnsHardVersion {
        public void solve(int testNumber, FastReader in, PrintWriter out) {
            int n = in.nextInt();
            int m = in.nextInt();
            E2RotateColumnsHardVersion.Column[] columns = new E2RotateColumnsHardVersion.Column[m];
            for (int i = 0; i < columns.length; ++i) columns[i] = new E2RotateColumnsHardVersion.Column(new int[n]);
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    columns[j].v[i] = in.nextInt();
                    if (i == n - 1) columns[j].initMax();
                }
            }
            Arrays.sort(columns, (o1, o2) -> o2.max - o1.max);
            if (columns.length > n)
                columns = Arrays.copyOf(columns, n);

            long[] dp = new long[1 << n];
            for (E2RotateColumnsHardVersion.Column c : columns) {
                long[] ndp = new long[1 << n];
                System.arraycopy(dp, 0, ndp, 0, dp.length);

                for (int rot = 0; rot < n; ++rot) {
                    long[] temp = new long[1 << n];
                    System.arraycopy(dp, 0, temp, 0, dp.length);
                    for (int i = 0, pos = rot; i < n; ++i, ++pos) {
                        if (pos >= n) pos = 0;
                        int val = c.v[pos];
                        for (int j = 0; j < temp.length; ++j) {
                            if ((j & (1 << i)) == 0)
                                temp[j | (1 << i)] = Math.max(temp[j | (1 << i)], temp[j] + val);
                        }
                    }
                    for (int i = 0; i < ndp.length; ++i)
                        ndp[i] = Math.max(ndp[i], temp[i]);
                }
                dp = ndp;
            }
            out.println(dp[dp.length - 1]);
        }

        static class Column {
            int[] v;
            int max;

            public Column(int[] v) {
                this.v = v;
            }

            void initMax() {
                max = 0;
                for (int vv : v) max = Math.max(max, vv);
            }

        }

    }

    static class FastReader {
        private InputStream stream;
        private byte[] buf = new byte[8192];
        private int curChar;
        private int pnumChars;

        public FastReader(InputStream stream) {
            this.stream = stream;
        }

        private int pread() {
            if (pnumChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= pnumChars) {
                curChar = 0;
                try {
                    pnumChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (pnumChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public String next() {
            return nextString();
        }

        public int nextInt() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = pread();
            }
            int res = 0;
            do {
                if (c == ',') {
                    c = pread();
                }
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = pread();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public String nextString() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = pread();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        private boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        Scanner in = new Scanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E1RotateColumnsEasyVersion solver = new E1RotateColumnsEasyVersion();
        solver.solve(1, in, out);
        out.close();
    }

    static class E1RotateColumnsEasyVersion {
        int n;
        int m;
        int[][] arr;
        int[][] mskValue;
        int[][] memo;

        public void solve(int testNumber, Scanner sc, PrintWriter pw) {
            int q = sc.nextInt();
            while (q-- > 0) {
                n = sc.nextInt();
                m = sc.nextInt();
                arr = new int[n][m];
                for (int i = 0; i < n; i++)
                    for (int j = 0; j < m; j++)
                        arr[i][j] = sc.nextInt();
                int[][] temp = new int[m][n];
                for (int i = 0; i < m; i++)
                    for (int j = 0; j < n; j++)
                        temp[i][j] = arr[j][i];
                Arrays.sort(temp, (a, b) -> getMax(b) - getMax(a));
                for (int i = 0; i < m; i++)
                    for (int j = 0; j < n; j++)
                        arr[j][i] = temp[i][j];
                mskValue = new int[n][1 << n];
                for (int i = 0; i < Math.min(n, m); i++) {
                    for (int j = 0; j < 1 << n; j++) {
                        int max = 0;
                        for (int shift = 0; shift < n; shift++) {
                            int sum = 0;
                            for (int k = 0; k < n; k++)
                                if ((j & 1 << k) != 0)
                                    sum += arr[(k + shift) % n][i];
                            max = Math.max(max, sum);
                        }
                        mskValue[i][j] = max;
                    }
                }
                memo = new int[Math.min(n, m)][1 << n];
                for (int[] x : memo)
                    Arrays.fill(x, -1);
                pw.println(dp(0, 0));
            }
        }

        private int getMax(int[] a) {
            int max = 0;
            for (int x : a)
                max = Math.max(max, x);
            return max;
        }

        private int dp(int idx, int msk) {
            if (msk == (1 << n) - 1)
                return 0;
            if (idx == Math.min(n, m))
                return (int) -1e9;
            int max = Integer.MIN_VALUE;
            if (memo[idx][msk] != -1)
                return memo[idx][msk];
            int availableBits = msk ^ ((1 << n) - 1);
            for (int colMask = availableBits; colMask != 0; colMask = (colMask - 1) & availableBits) {

                max = Math.max(max, mskValue[idx][colMask] + dp(idx + 1, msk | colMask));

            }
            return memo[idx][msk] = max;
        }

    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

        public Scanner(FileReader r) {
            br = new BufferedReader(r);
        }

        public Scanner(InputStream s) {
            br = new BufferedReader(new InputStreamReader(s));
        }

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

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

    }
}


//stan hu tao
//join nct ridin by first year culture reps
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.abs;
import static java.lang.System.out;
import java.util.*;
import java.io.*;
import java.math.*;

public class x1209E
{
    public static void main(String hi[]) throws Exception
    {
        BufferedReader infile = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(infile.readLine());
        int T = Integer.parseInt(st.nextToken());
        StringBuilder sb = new StringBuilder();
        while(T-->0)
        {
            st = new StringTokenizer(infile.readLine());
            int N = Integer.parseInt(st.nextToken());
            int M = Integer.parseInt(st.nextToken());
            int[][] grid = new int[N][M];
            for(int r=0; r < N; r++)
                grid[r] = readArr(M, infile, st);
            ArrayList<Integer> ls = new ArrayList<Integer>();
            for(int i=0; i < M; i++)
                ls.add(i);
            Collections.sort(ls, (x,y) -> {
                int m1 = grid[0][x];
                int m2 = grid[0][y];
                for(int r=1; r < N; r++)
                {
                    m1 = max(m1, grid[r][x]);
                    m2 = max(m2, grid[r][y]);
                }
                return m2-m1;
            });
            int[][] newgrid = new int[N][M];
            for(int r=0; r < N; r++)
                for(int c=0; c < M; c++)
                    newgrid[r][c] = grid[r][ls.get(c)];
            M = min(M, N);
            int[][] sums = new int[M][1<<N];
            for(int i=1; i < M; i++)
                for(int mask=0; mask < 1<<N; mask++)
                {
                    //try all shifts
                    for(int head=0; head < N; head++)
                    {
                        int temp = 0;
                        for(int b=0; b < N; b++)
                        {
                            int nb = b+head;
                            if(nb >= N)
                                nb -= N;
                            if((mask&(1<<nb)) > 0)
                                temp += newgrid[b][i];
                        }
                        sums[i][mask] = max(sums[i][mask], temp);
                    }
                }
            int[][] dp = new int[M][1<<N];
            for(int mask=0; mask < 1<<N; mask++)
                for(int b=0; b < N; b++)
                    if((mask&(1<<b)) > 0)
                        dp[0][mask] += newgrid[b][0];
            for(int i=1; i < M; i++)
                for(int mask=0; mask < 1<<N; mask++)
                    for(int pmask=mask; pmask >= 0; pmask=(pmask-1)&mask)
                    {
                        dp[i][mask] = max(dp[i][mask], dp[i-1][pmask]+sums[i][mask-pmask]);
                        if(pmask == 0)
                            break;
                    }
            sb.append(dp[M-1][(1<<N)-1]+"\n");
        }
        System.out.print(sb);
    }
    public static int[] readArr(int N, BufferedReader infile, StringTokenizer st) throws Exception
    {
        int[] arr = new int[N];
        st = new StringTokenizer(infile.readLine());
        for(int i=0; i < N; i++)
            arr[i] = Integer.parseInt(st.nextToken());
        return arr;
    }
}


import static java.lang.Integer.parseInt;
import static java.lang.Long.parseLong;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.System.exit;
import static java.util.Arrays.fill;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

public class E {

	static void solve() throws Exception {
		int tests = scanInt();
//		int tests = 40;
		for (int test = 0; test < tests; test++) {
			int n = scanInt(), m = scanInt(), a[][] = new int[n][m];
//			int n = 12, m = 2000, a[][] = new int[n][m];
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					a[i][j] = scanInt();
				}
			}
			int bestCols[] = new int[min(m, n)];
			for (int i = 0; i < bestCols.length; i++) {
				bestCols[i] = i;
			}
			if (m > n) {
				int bestColMax[] = new int[n];
				for (int i = 0; i < n; i++) {
					int cmax = 0;
					for (int j = 0; j < n; j++) {
						cmax = max(cmax, a[j][i]);
					}
					bestColMax[i] = cmax;
				}
				for (int i = n; i < m; i++) {
					int cmax = 0;
					for (int j = 0; j < n; j++) {
						cmax = max(cmax, a[j][i]);
					}
					int minBC = 0, minBCM = Integer.MAX_VALUE;
					for (int j = 0; j < n; j++) {
						if (bestColMax[j] < minBCM) {
							minBC = j;
							minBCM = bestColMax[j];
						}
					}
					if (cmax > minBCM) {
						bestCols[minBC] = i;
						bestColMax[minBC] = cmax;
					}
				}
			}
			int dyn[] = new int[1 << n], dynNext[] = new int[1 << n], sums[] = new int[1 << n], csums[] = new int[1 << n];
			for (int i: bestCols) {
				fill(dynNext, 0);
				fill(sums, 0);
				for (int j = 0; j < n; j++) {
					for (int k = 1, bit = 0; k < 1 << n; k++) {
						if (k == 1 << (bit + 1)) {
							++bit;
						}
						sums[k] = max(sums[k], csums[k] = csums[k ^ (1 << bit)] + a[(bit + j) % n][i]);
					}
				}
				for (int mask1 = 0; mask1 < 1 << n; mask1++) {
					int cdyn = dynNext[mask1];
					for (int mask2 = mask1;; mask2 = (mask2 - 1) & mask1) {
						cdyn = max(cdyn, dyn[mask2] + sums[mask1 ^ mask2]);
						if (mask2 == 0) {
							break;
						}
					}
					dynNext[mask1] = cdyn;
				}
				int t[] = dyn;
				dyn = dynNext;
				dynNext = t;
			}
			out.println(dyn[(1 << n) - 1]);
		}
	}

	static int scanInt() throws IOException {
		return parseInt(scanString());
	}

	static long scanLong() throws IOException {
		return parseLong(scanString());
	}

	static String scanString() throws IOException {
		while (tok == null || !tok.hasMoreTokens()) {
			tok = new StringTokenizer(in.readLine());
		}
		return tok.nextToken();
	}

	static BufferedReader in;
	static PrintWriter out;
	static StringTokenizer tok;

	public static void main(String[] args) {
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
			in.close();
			out.close();
		} catch (Throwable e) {
			e.printStackTrace();
			exit(1);
		}
	}
}


//package round584;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

// imp:12m
public class E4 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		for(int T = ni(); T> 0;T--){
			int n = ni(), m = ni();
			int[][] a = new int[n][];
			for(int i = 0;i < n;i++)a[i] = na(m);

			long[] mx = new long[m];
			for(int i = 0;i < m;i++){
				int u = 0;
				for(int j = 0;j < n;j++){
					u = Math.max(u, a[j][i]);
				}
				mx[i] = 1000000000L-u<<32|i;
			}
			Arrays.sort(mx);
			int[] dp = new int[1<<n];
			for(int i = 0;i < n && i < m;i++){
				int c = (int)mx[i];
				int[] ls = new int[1<<n];
				for(int j = 1;j < 1<<n;j++){
					ls[j] = ls[j&j-1] + a[Integer.numberOfTrailingZeros(j)][c];
				}
				for(int j = 1;j < 1<<n;j++){
					int r = rot(j, n);
					ls[r] = Math.max(ls[r], ls[j]);
				}
				int[] ndp = new int[1<<n];
				for(int j = 0;j < 1<<n;j++){
					if(rot(j, n) == j){
						int cur = j;
						for(int sh = 0;sh < n;sh++){
							cur = cur>>1|(cur&1)<<n-1;
							int mask = (1<<n)-1^cur;
							for(int k = mask;k >= 0;k--){
								k &= mask;

								ndp[k|cur] = Math.max(
										ndp[k|cur], dp[k] + ls[j]);
							}
						}
					}
				}
				dp = ndp;
			}
			out.println(dp[(1<<n)-1]);
		}
	}

	int rot(int x, int n)
	{
		int ret = x;
		for(int i = 0;i < n;i++){
			x = x>>>1|(x&1)<<n-1;
				ret = Math.min(ret, x);
		}
		return ret;
	}

	void run() throws Exception
	{
//		int n = 12, m = 2000;
//		Random gen = new Random();
//		StringBuilder sb = new StringBuilder();
//		sb.append(40 + " ");
//		for(int rep = 0;rep < 40;rep++){
//			sb.append(n + " ");
//			sb.append(m + " ");
//			for (int i = 0; i < n*m; i++) {
//				sb.append(gen.nextInt(100000) + " ");
//			}
//		}
//		INPUT = sb.toString();

		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E4().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


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

public class Main{
	static int[][]memo;
	static int n,m,in[][];
	static int dp(int col,int maxRowMask) {
		if(col>=Math.min(n, m) || maxRowMask==((1<<n)-1))return 0;
		if(memo[col][maxRowMask]!=-1)return memo[col][maxRowMask];

		int ans=0;

		int availableBits=maxRowMask^((1<<n)-1);
		//all masks that don't intersect with maxRowMask
		for(int colMask=availableBits;colMask!=0;colMask=(colMask-1)&availableBits) {

			ans=Math.max(ans, maxMask[col][colMask]+dp(col+1, maxRowMask|colMask));

		}
		return memo[col][maxRowMask]=ans;
	}
	static int[][]sumOfMask;
	static int[][]maxMask;
	public static void main(String[] args) throws Exception{
		pw=new PrintWriter(System.out);
		sc = new MScanner(System.in);
		int tc=sc.nextInt();
		while(tc-->0) {
			n=sc.nextInt();m=sc.nextInt();

			int[]maxInCol=new int[m];
			in=new int[m][n+1];

			for(int i=0;i<n;i++) {
				for(int j=0;j<m;j++) {
					in[j][i]=sc.nextInt();
					maxInCol[j]=Math.max(maxInCol[j], in[j][i]);
					in[j][n]=j;
				}
			}
			Arrays.sort(in,(x,y)->maxInCol[y[n]]-maxInCol[x[n]]);

			memo=new int[n][1<<n];
			sumOfMask=new int[n][1<<n];
			maxMask=new int[n][1<<n];
			for(int i=0;i<n;i++) {
				for(int msk=0;msk<memo[i].length;msk++) {
					memo[i][msk]=-1;
					if(i>=m)continue;
					for(int bit=0;bit<n;bit++) {
						if(((msk>>bit)&1)!=0) {
							sumOfMask[i][msk]+=in[i][bit];
						}
					}
				}
			}
			for(int col=0;col<n;col++) {
				for(int msk=0;msk<(1<<n);msk++) {
					int curMask=msk;
					for(int cyclicShift=0;cyclicShift<n;cyclicShift++) {
						maxMask[col][msk]=Math.max(maxMask[col][msk], sumOfMask[col][curMask]);

						int lastBit=curMask&1;
						curMask>>=1;
						curMask|=(lastBit<<(n-1));

					}
				}
			}
			pw.println(dp(0, 0));
		}

		pw.flush();
	}
	static PrintWriter pw;
	static MScanner  sc;
	static class MScanner {
		StringTokenizer st;
		BufferedReader br;
		public MScanner(InputStream system) {
			br = new BufferedReader(new InputStreamReader(system));
		}

		public MScanner(String file) throws Exception {
			br = new BufferedReader(new FileReader(file));
		}

		public String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}
		public int[] intArr(int n) throws IOException {
	        int[]in=new int[n];for(int i=0;i<n;i++)in[i]=nextInt();
	        return in;
		}
		public long[] longArr(int n) throws IOException {
	        long[]in=new long[n];for(int i=0;i<n;i++)in[i]=nextLong();
	        return in;
		}
		public int[] intSortedArr(int n) throws IOException {
	        int[]in=new int[n];for(int i=0;i<n;i++)in[i]=nextInt();
	        shuffle(in);
	        Arrays.sort(in);
	        return in;
		}
		public long[] longSortedArr(int n) throws IOException {
	        long[]in=new long[n];for(int i=0;i<n;i++)in[i]=nextLong();
	        shuffle(in);
	        Arrays.sort(in);
	        return in;
		}
		public Integer[] IntegerArr(int n) throws IOException {
	        Integer[]in=new Integer[n];for(int i=0;i<n;i++)in[i]=nextInt();
	        return in;
		}
		public Long[] LongArr(int n) throws IOException {
	        Long[]in=new Long[n];for(int i=0;i<n;i++)in[i]=nextLong();
	        return in;
		}
		public String nextLine() throws IOException {
			return br.readLine();
		}

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

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

		public char nextChar() throws IOException {
			return next().charAt(0);
		}

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

		public boolean ready() throws IOException {
			return br.ready();
		}

		public void waitForInput() throws InterruptedException {
			Thread.sleep(3000);
		}
	}
	static void shuffle(int[]in) {
		for(int i=0;i<in.length;i++) {
			int idx=(int)(Math.random()*in.length);
			int tmp=in[i];
			in[i]=in[idx];
			in[idx]=tmp;
		}
	}
	static void shuffle(long[]in) {
		for(int i=0;i<in.length;i++) {
			int idx=(int)(Math.random()*in.length);
			long tmp=in[i];
			in[i]=in[idx];
			in[idx]=tmp;
		}
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Comparator;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastReader in = new FastReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2RotateColumnsHardVersion solver = new E2RotateColumnsHardVersion();
        int testCount = Integer.parseInt(in.next());
        for (int i = 1; i <= testCount; i++)
            solver.solve(i, in, out);
        out.close();
    }

    static class E2RotateColumnsHardVersion {
        public void solve(int testNumber, FastReader in, PrintWriter out) {
            int n = in.nextInt();
            int m = in.nextInt();
            E2RotateColumnsHardVersion.Column[] columns = new E2RotateColumnsHardVersion.Column[m];
            for (int i = 0; i < columns.length; ++i) columns[i] = new E2RotateColumnsHardVersion.Column(new int[n]);
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    columns[j].vals[i] = in.nextInt();
                }
            }
            for (E2RotateColumnsHardVersion.Column column : columns) column.initMax();
            Arrays.sort(columns, new Comparator<E2RotateColumnsHardVersion.Column>() {

                public int compare(E2RotateColumnsHardVersion.Column o1, E2RotateColumnsHardVersion.Column o2) {
                    return o2.max - o1.max;
                }
            });
            if (columns.length > n)
                columns = Arrays.copyOf(columns, n);
            out.println(solveOne(columns));
        }

        private int solveOne(E2RotateColumnsHardVersion.Column[] columns) {
            int n = columns[0].vals.length;
            int[] best = new int[1 << n];
            int[] next = new int[1 << n];
            int[] temp = new int[1 << n];

            for (E2RotateColumnsHardVersion.Column nowColumn : columns) {
                System.arraycopy(best, 0, next, 0, best.length);
                for (int rot = 0; rot < n; ++rot) {
                    System.arraycopy(best, 0, temp, 0, next.length);
                    for (int i = 0, pos = rot; i < n; ++i, ++pos) {
                        if (pos >= n) pos = 0;
                        int val = nowColumn.vals[pos];
                        for (int j = 0; j < temp.length; ++j) {
                            if ((j & (1 << i)) == 0) {
                                temp[j | (1 << i)] = Math.max(temp[j | (1 << i)], temp[j] + val);
                            }
                        }
                    }
                    for (int j = 0; j < temp.length; ++j) {
                        next[j] = Math.max(next[j], temp[j]);
                    }
                }
                int[] aa = best;
                best = next;
                next = aa;
            }
            return best[best.length - 1];
        }

        static class Column {
            int[] vals;
            int max;

            public Column(int[] vals) {
                this.vals = vals;
            }

            void initMax() {
                max = 0;
                for (int vv : vals) max = Math.max(max, vv);
            }

        }

    }

    static class FastReader {
        private InputStream stream;
        private byte[] buf = new byte[8192];
        private int curChar;
        private int pnumChars;

        public FastReader(InputStream stream) {
            this.stream = stream;
        }

        private int pread() {
            if (pnumChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= pnumChars) {
                curChar = 0;
                try {
                    pnumChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (pnumChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public String next() {
            return nextString();
        }

        public int nextInt() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = pread();
            }
            int res = 0;
            do {
                if (c == ',') {
                    c = pread();
                }
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = pread();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public String nextString() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = pread();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        private boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.FilterInputStream;
import java.io.BufferedInputStream;
import java.util.Random;
import java.io.InputStream;

/**
 * @author khokharnikunj8
 */

public class Main {
    public static void main(String[] args) {
        new Thread(null, new Runnable() {
            public void run() {
                new Main().solve();
            }
        }, "1", 1 << 26).start();
    }

    void solve() {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        ScanReader in = new ScanReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2RotateColumnsHardVersion solver = new E2RotateColumnsHardVersion();
        int testCount = in.scanInt();
        for (int i = 1; i <= testCount; i++)
            solver.solve(i, in, out);
        out.close();
    }

    static class E2RotateColumnsHardVersion {
        int[][] dp;
        int[] cur;

        public void solve(int testNumber, ScanReader in, PrintWriter out) {
            int n = in.scanInt();
            int m = in.scanInt();
            int[][] ar = new int[n][m];
            int[][] max = new int[m][2];
            for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                    ar[i][j] = in.scanInt();
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) max[i][0] = Math.max(max[i][0], ar[j][i]);
                max[i][1] = i;
            }
            CodeHash.shuffle(max);
            Arrays.sort(max, (o1, o2) -> -o1[0] + o2[0]);
            dp = new int[2][1 << n];
            cur = new int[1 << n];
            for (int i = 0; i < Math.min(m, n); i++) {
                Arrays.fill(cur, 0);
                Arrays.fill(dp[i & 1], 0);
                for (int j = 0; j < 1 << n; j++) {
                    for (int k = 0; k < n; k++) {
                        int sum = 0;
                        for (int l = 0; l < n; l++) {
                            if ((j & (1 << l)) != 0) {
                                sum += (ar[(k + l) % n][max[i][1]]);
                            }
                        }
                        cur[j] = Math.max(cur[j], sum);
                    }
                }
                for (int j = 0; j < (1 << n); j++) {
                    for (int k = j; ; k = (k - 1) & j) {
                        dp[i & 1][j] = Math.max(dp[i & 1][j], dp[(i - 1) & 1][k] + cur[j ^ k]);
                        if (k == 0) break;
                    }
                }
            }
            out.println(dp[Math.min(n, m) & 1 ^ 1][(1 << n) - 1]);
        }

    }

    static class CodeHash {
        public static void shuffle(int[][] ar) {
            Random rd = new Random(new Random().nextInt());
            for (int i = 0; i < ar.length; i++) {
                int index = rd.nextInt(ar.length);
                int[] temp = ar[i];
                ar[i] = ar[index];
                ar[index] = temp;
            }
        }

    }

    static class ScanReader {
        private byte[] buf = new byte[4 * 1024];
        private int index;
        private BufferedInputStream in;
        private int total;

        public ScanReader(InputStream inputStream) {
            in = new BufferedInputStream(inputStream);
        }

        private int scan() {
            if (index >= total) {
                index = 0;
                try {
                    total = in.read(buf);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if (total <= 0) return -1;
            }
            return buf[index++];
        }

        public int scanInt() {
            int integer = 0;
            int n = scan();
            while (isWhiteSpace(n)) n = scan();
            int neg = 1;
            if (n == '-') {
                neg = -1;
                n = scan();
            }
            while (!isWhiteSpace(n)) {
                if (n >= '0' && n <= '9') {
                    integer *= 10;
                    integer += n - '0';
                    n = scan();
                }
            }
            return neg * integer;
        }

        private boolean isWhiteSpace(int n) {
            if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
            else return false;
        }

    }
}


import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;

public class Test {
  static PrintWriter writer =
      new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
  int[][] a = new int[12][2000];
  int[][] e = new int[12 * 2000][3];
  Integer[] se = new Integer[12 * 2000];
  boolean[] used = new boolean[2000];
  int[] dp = new int[1 << 12];
  int[] one = new int[1 << 12];

  static int readInt() {
    int ans = 0;
    boolean neg = false;
    try {
      boolean start = false;
      for (int c = 0; (c = System.in.read()) != -1; ) {
        if (c == '-') {
          start = true;
          neg = true;
          continue;
        } else if (c >= '0' && c <= '9') {
          start = true;
          ans = ans * 10 + c - '0';
        } else if (start) break;
      }
    } catch (IOException e) {
    }
    return neg ? -ans : ans;
  }

  static long readLong() {
    long ans = 0;
    boolean neg = false;
    try {
      boolean start = false;
      for (int c = 0; (c = System.in.read()) != -1; ) {
        if (c == '-') {
          start = true;
          neg = true;
          continue;
        } else if (c >= '0' && c <= '9') {
          start = true;
          ans = ans * 10 + c - '0';
        } else if (start) break;
      }
    } catch (IOException e) {
    }
    return neg ? -ans : ans;
  }

  static String readLine() {
    StringBuilder b = new StringBuilder();
    try {
      boolean start = false;
      for (int c = 0; (c = System.in.read()) != -1; ) {
        if (Character.isLetterOrDigit(c)) {
          start = true;
          b.append((char) c);
        } else if (start) break;
      }
    } catch (IOException e) {
    }
    return b.toString();
  }

  public static void main(String[] args) {
    Test te = new Test();
    te.start();
    writer.flush();
  }

  void start() {
    int t = readInt();
    while (t-- > 0) {
      int n = readInt(), m = readInt();
      for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++) {
          a[i][j] = readInt();
          int k = i * m + j;
          e[k][0] = a[i][j];
          e[k][1] = j;
          e[k][2] = i;
        }
      for (int i = n * m - 1; i >= 0; i--) se[i] = i;
      Arrays.sort(
          se,
          0,
          n * m,
          (i, j) -> {
            int[] x = e[i], y = e[j];
            return x[0] == y[0]
                ? (x[1] == y[1] ? Integer.compare(x[2], y[2]) : Integer.compare(x[1], y[1]))
                : Integer.compare(x[0], y[0]);
          });
      Arrays.fill(used, 0, m, false);
      Arrays.fill(dp, 0, 1 << n, -1);
      dp[0] = 0;
      int cc = 0;
      for (int x = n * m - 1; x >= 0; x--) {
        int c = e[se[x]][1];
        if (used[c]) continue;
        used[c] = true;
        cc++;
        if (cc > n) break;

        Arrays.fill(one, 0, 1 << n, 0);

        for (int i = (1 << n) - 1; i > 0; i--) {
          for (int r = 0; r < n; r++) {
            int sum = 0;
            for (int j = 0; j < n; j++) if (((i >> j) & 1) != 0) sum += a[(j + r) % n][c];
            one[i] = Math.max(one[i], sum);
          }
        }

        for (int i = (1 << n) - 1; i >= 0; i--) {
          int u = (1 << n) - 1 - i;
          int p = u;
          if (dp[i] >= 0)
            while (p > 0) {
              dp[i | p] = Math.max(dp[i | p], dp[i] + one[p]);
              p = (p - 1) & u;
            }
        }
      }
      writer.println(dp[(1 << n) - 1]);
    }
  }
}


import java.util.*;
import java.io.*;
public class E {

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		ArrayList<Integer>[][] nexts = new ArrayList[13][];
		ArrayList<Integer>[] bs = new ArrayList[13];
		int[][] index = new int[13][];
		int[][] eqcl = new int[13][];
		for(int n = 1; n <= 12; n++) {
			eqcl[n] = new int[(1 << n)];
			bs[n] = new ArrayList<Integer>();
			index[n] = new int[(1 << n)];
			int ind = 0;
			for(int mask = 0; mask < (1 << n); mask++) {
				boolean add = true;
				for(int k = 0; k < n; k++) {
					if(rot(mask, k, n) < mask) add = false;
				}
				if(add) {
					bs[n].add(mask);
					index[n][mask] = ind; ind++;
				}
			}
			nexts[n] = new ArrayList[bs[n].size()];
			for(int i = 0; i < bs[n].size(); i++) {
				int mask = bs[n].get(i);
				for(int k = 0; k < n; k++) {
					eqcl[n][rot(mask, k, n)] = mask;
				}
				nexts[n][i] = new ArrayList<>();
				for(int y = 0; y < (1 << n); y++) {
					if((mask & y) == 0) {
						nexts[n][i].add(y);
					}
				}
			}
		}
		int T = Integer.parseInt(br.readLine());
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		for(int test = 0; test < T; test++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int n = Integer.parseInt(st.nextToken());
			int m = Integer.parseInt(st.nextToken());
			int[][] arrt = new int[m][n];
			for(int i = 0; i < n; i++) {
				st = new StringTokenizer(br.readLine());
				for(int j = 0; j < m; j++) {
					arrt[j][i] = Integer.parseInt(st.nextToken());
				}
			}
			Column[] cols = new Column[m];
			for(int j = 0; j < m; j++) {
				cols[j] = new Column(arrt[j]);
			}
			Arrays.sort(cols, Collections.reverseOrder());
			m = Integer.min(n, m);
			int[][] arr = new int[n][m];
			for(int i = 0; i < n; i++) {
				for(int j = 0; j < m; j++) {
					arr[i][j] = cols[j].arr[i];
				}
			}
			int[][] max = new int[m][bs[n].size()];
			for(int c = 0; c < m; c++) {
				for(int mask = 0; mask < (1 << n); mask++) {
					int curr = 0;
					for(int i = 0; i < n; i++) {
						if((mask & (1 << i)) > 0) curr += arr[i][c];
					}
					int cl = eqcl[n][mask];
					max[c][index[n][cl]] = Integer.max(max[c][index[n][cl]], curr);
				}
			}
			int[][] dp = new int[m+1][bs[n].size()];
			for(int c = 0; c < m; c++) {
				for(int i = 0; i < bs[n].size(); i++) {
					int mask = bs[n].get(i);
					for(int next: nexts[n][i]) {
						int cl = eqcl[n][next];
						int dl = eqcl[n][mask | next];
						if(dp[c][i] + max[c][index[n][cl]] > dp[c+1][index[n][dl]]) {
							dp[c+1][index[n][dl]] = dp[c][i] + max[c][index[n][cl]];
						}
					}
				}
			}
			bw.write(dp[m][bs[n].size() - 1]+"\n");
		}
		bw.flush();
	}
	static int rot(int x, int k, int n) {
		int a = x << k;
		int b = x >> (n - k);
		return (a + b) & ((1 << n) - 1);
	}
	static class Column implements Comparable<Column>{
		int[] arr;
		int max;
		public Column(int[] arr) {
			this.arr = arr;
			max = 0;
			for(int k: arr) {
				max = Integer.max(max, k);
			}
		}
		@Override
		public int compareTo(Column col) {
			return max - col.max;
		}
	}
}


//package round584;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.InputMismatchException;

// imp:12m
public class E5 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		for(int T = ni(); T> 0;T--){
			int n = ni(), m = ni();
			int[][] a = new int[m][n];
			for(int i = 0;i < n;i++){
				for(int j = 0;j < m;j++){
					a[j][i] = ni();
				}
			}

			int[][] mx = new int[m][];
			for(int i = 0;i < m;i++){
				int u = 0;
				for(int j = 0;j < n;j++){
					u = Math.max(u, a[i][j]);
				}
				mx[i] = new int[]{u, i};
			}
			Arrays.sort(mx, new Comparator<int[]>() {
				public int compare(int[] a, int[] b) {
					return -(a[0] - b[0]);
				}
			});
			int[] dp = new int[1<<n];
			for(int i = 0;i < n && i < m;i++){
				int c = mx[i][1];
				int[] ls = new int[1<<n];
				for(int j = 1;j < 1<<n;j++){
					ls[j] = ls[j&j-1] + a[c][Integer.numberOfTrailingZeros(j)];
				}
				for(int j = 1;j < 1<<n;j++){
					int r = rot(j, n);
					ls[r] = Math.max(ls[r], ls[j]);
				}
				int[] ndp = new int[1<<n];
				for(int j = 0;j < 1<<n;j++){
					if(rot(j, n) == j){
						int cur = j;
						for(int sh = 0;sh < n;sh++){
							cur = cur>>1|(cur&1)<<n-1;
							int mask = (1<<n)-1^cur;
							for(int k = mask;k >= 0;k--){
								k &= mask;

								ndp[k|cur] = Math.max(
										ndp[k|cur], dp[k] + ls[j]);
							}
						}
					}
				}
				dp = ndp;
			}
			out.println(dp[(1<<n)-1]);
		}
	}

	int rot(int x, int n)
	{
		int ret = x;
		for(int i = 0;i < n;i++){
			x = x>>>1|(x&1)<<n-1;
				ret = Math.min(ret, x);
		}
		return ret;
	}

	void run() throws Exception
	{
//		int n = 12, m = 2000;
//		Random gen = new Random();
//		StringBuilder sb = new StringBuilder();
//		sb.append(40 + " ");
//		for(int rep = 0;rep < 40;rep++){
//			sb.append(n + " ");
//			sb.append(m + " ");
//			for (int i = 0; i < n*m; i++) {
//				sb.append(gen.nextInt(100000) + " ");
//			}
//		}
//		INPUT = sb.toString();

		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E5().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


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

public class Main {
	public static void main(String args[]) {new Main().run();}

	FastReader in = new FastReader();
	PrintWriter out = new PrintWriter(System.out);
	void run(){
		int t=in.nextInt();
		for(int i=0;i<t;i++) {
			out.println(work());
		}
		out.flush();
	}
	long mod=1000000007;
	long gcd(long a,long b) {
		return b==0?a:gcd(b,a%b);
	}
	int work() {
		int n=in.nextInt();
		int m=in.nextInt();
		int[][] A=new int[n][m];
		int[][] B=new int[n][m];
		int[][] R=new int[m][2];
		for(int i=0;i<m;i++)R[i][1]=i;
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				A[i][j]=in.nextInt();
				R[j][0]=Math.max(R[j][0], A[i][j]);
			}
		}
		Arrays.sort(R,new Comparator<int[]>() {
			public int compare(int[] arr1,int[] arr2) {
				return arr2[0]-arr1[0];
			}
		});
		for(int j=0;j<m;j++) {
			int index=R[j][1];
			for(int i=0;i<n;i++) {
				B[i][j]=A[i][index];
			}
		}
		m=Math.min(n, m);
		int[][] dp=new int[m][1<<n];
		int[][] rec=new int[m][1<<n];
		for(int j=0;j<m;j++) {
			for(int s=0;s<n;s++) {//转
				for(int i=1;i<1<<n;i++) {
					int sum=0;
					for(int b=0;b<n;b++) {
						if(((1<<b)&i)>0) {
							sum+=B[(b+s)%n][j];
						}
					}
					rec[j][i]=Math.max(sum, rec[j][i]);
				}
			}
		}

		for(int j=0;j<m;j++) {
			for(int i=0;i<1<<n;i++) {
				if(j==0) {
					dp[j][i]=rec[j][i];
				}else {
					for(int p=i+1;;p++) {
						if(p>=1<<n)break;
						p=p|i;
						dp[j][p]=Math.max(dp[j][p], rec[j][i]+dp[j-1][p^i]);
					}
				}
			}
		}
		return dp[m-1][(1<<n)-1];
	}
}

class FastReader
{
	BufferedReader br;
	StringTokenizer st;

	public FastReader()
	{
		br=new BufferedReader(new InputStreamReader(System.in));
	}

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

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

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


//package round584;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.InputMismatchException;

public class E4 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		for(int T = ni(); T> 0;T--){
			int n = ni(), m = ni();
			int[][] a = new int[n][];
			for(int i = 0;i < n;i++)a[i] = na(m);

			int[][] mx = new int[m][];
			for(int i = 0;i < m;i++){
				int u = 0;
				for(int j = 0;j < n;j++){
					u = Math.max(u, a[j][i]);
				}
				mx[i] = new int[]{u, i};
			}
			Arrays.sort(mx, new Comparator<int[]>() {
				public int compare(int[] a, int[] b) {
					return -(a[0] - b[0]);
				}
			});
			int[] dp = new int[1<<n];
			for(int i = 0;i < n && i < m;i++){
				int c = mx[i][1];
				int[] ls = new int[1<<n];
				for(int j = 1;j < 1<<n;j++){
					ls[j] = ls[j&j-1] + a[Integer.numberOfTrailingZeros(j)][c];
				}
				for(int j = 1;j < 1<<n;j++){
					int r = rot(j, n);
					ls[r] = Math.max(ls[r], ls[j]);
				}
				int[] ndp = new int[1<<n];
				for(int j = 0;j < 1<<n;j++){
					if(rot(j, n) == j){
						int cur = j;
						for(int sh = 0;sh < n;sh++){
							cur = cur>>1|(cur&1)<<n-1;
							int mask = (1<<n)-1^cur;
							for(int k = mask;k >= 0;k--){
								k &= mask;

								ndp[k|cur] = Math.max(
										ndp[k|cur], dp[k] + ls[j]);
							}
						}
					}
				}
				dp = ndp;
			}
			out.println(dp[(1<<n)-1]);
		}
	}

	int rot(int x, int n)
	{
		int ret = x;
		for(int i = 0;i < n;i++){
			x = x>>>1|(x&1)<<n-1;
				ret = Math.min(ret, x);
		}
		return ret;
	}

	void run() throws Exception
	{
//		int n = 12, m = 2000;
//		Random gen = new Random();
//		StringBuilder sb = new StringBuilder();
//		sb.append(40 + " ");
//		for(int rep = 0;rep < 40;rep++){
//			sb.append(n + " ");
//			sb.append(m + " ");
//			for (int i = 0; i < n*m; i++) {
//				sb.append(gen.nextInt(100000) + " ");
//			}
//		}
//		INPUT = sb.toString();

		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new E4().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.Comparator;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastReader in = new FastReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        E2RotateColumnsHardVersion solver = new E2RotateColumnsHardVersion();
        int testCount = Integer.parseInt(in.next());
        for (int i = 1; i <= testCount; i++)
            solver.solve(i, in, out);
        out.close();
    }

    static class E2RotateColumnsHardVersion {
        public void solve(int testNumber, FastReader in, PrintWriter out) {
            int n = in.nextInt();
            int m = in.nextInt();
            E2RotateColumnsHardVersion.Column[] columns = new E2RotateColumnsHardVersion.Column[m];
            for (int i = 0; i < columns.length; ++i) columns[i] = new E2RotateColumnsHardVersion.Column(new int[n]);
            for (int i = 0; i < n; ++i) {
                for (int j = 0; j < m; ++j) {
                    columns[j].v[i] = in.nextInt();
                    if (i == n - 1) columns[j].initMax();
                }
            }
            Arrays.sort(columns, new Comparator<E2RotateColumnsHardVersion.Column>() {

                public int compare(E2RotateColumnsHardVersion.Column o1, E2RotateColumnsHardVersion.Column o2) {
                    return o2.max - o1.max;
                }
            });
            if (columns.length > n)
                columns = Arrays.copyOf(columns, n);

            long[] dp = new long[1 << n];
            for (E2RotateColumnsHardVersion.Column c : columns) {
                long[] ndp = new long[1 << n];
                System.arraycopy(dp, 0, ndp, 0, dp.length);

                for (int rot = 0; rot < n; ++rot) {
                    long[] temp = new long[1 << n];
                    System.arraycopy(dp, 0, temp, 0, dp.length);
                    for (int i = 0, pos = rot; i < n; ++i, ++pos) {
                        if (pos >= n) pos = 0;
                        int val = c.v[pos];
                        for (int j = 0; j < temp.length; ++j) {
                            if ((j & (1 << i)) == 0)
                                temp[j | (1 << i)] = Math.max(temp[j | (1 << i)], temp[j] + val);
                        }
                    }
                    for (int i = 0; i < ndp.length; ++i)
                        ndp[i] = Math.max(ndp[i], temp[i]);
                }
                dp = ndp;
            }
            out.println(dp[dp.length - 1]);
        }

        static class Column {
            int[] v;
            int max;

            public Column(int[] v) {
                this.v = v;
            }

            void initMax() {
                max = 0;
                for (int vv : v) max = Math.max(max, vv);
            }

        }

    }

    static class FastReader {
        private InputStream stream;
        private byte[] buf = new byte[8192];
        private int curChar;
        private int pnumChars;

        public FastReader(InputStream stream) {
            this.stream = stream;
        }

        private int pread() {
            if (pnumChars == -1) {
                throw new InputMismatchException();
            }
            if (curChar >= pnumChars) {
                curChar = 0;
                try {
                    pnumChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (pnumChars <= 0) {
                    return -1;
                }
            }
            return buf[curChar++];
        }

        public String next() {
            return nextString();
        }

        public int nextInt() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = pread();
            }
            int res = 0;
            do {
                if (c == ',') {
                    c = pread();
                }
                if (c < '0' || c > '9') {
                    throw new InputMismatchException();
                }
                res *= 10;
                res += c - '0';
                c = pread();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public String nextString() {
            int c = pread();
            while (isSpaceChar(c))
                c = pread();
            StringBuilder res = new StringBuilder();
            do {
                res.appendCodePoint(c);
                c = pread();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        private boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

    }
}


import java.util.*;
import java.io.*;
public class E1 {

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		//optimizaciones que parece que solo son necesarias para java
		ArrayList<Integer>[] reps = new ArrayList[13]; //representantes de las clases
		int[][] index = new int[13][]; // mapea para cada representante un indice de 0 a |clases|-1
		int[][] eqcl = new int[13][]; //mapea para cada mask, su clase
		ArrayList<Integer>[][] nexts = new ArrayList[13][];	//para cada clase, los masks compatibles
		for(int n = 1; n <= 12; n++) {
			eqcl[n] = new int[(1 << n)];
			reps[n] = new ArrayList<Integer>();
			index[n] = new int[(1 << n)];
			int ind = 0;
			for(int mask = 0; mask < (1 << n); mask++) {
				boolean add = true;
				for(int k = 0; k < n; k++) {
					if(rot(mask, k, n) < mask) add = false;
				}
				if(add) {
					reps[n].add(mask);
					index[n][mask] = ind; ind++;
				}
			}
			nexts[n] = new ArrayList[reps[n].size()];
			for(int i = 0; i < reps[n].size(); i++) {
				int mask = reps[n].get(i);
				for(int k = 0; k < n; k++) {
					eqcl[n][rot(mask, k, n)] = i;
				}
				nexts[n][i] = new ArrayList<>();
				for(int y = 0; y < (1 << n); y++) {
					if((mask & y) == 0) {
						nexts[n][i].add(y);
					}
				}
			}
		}
		int T = Integer.parseInt(br.readLine());
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		for(int test = 0; test < T; test++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int n = Integer.parseInt(st.nextToken());
			int m = Integer.parseInt(st.nextToken());
			int[][] arrt = new int[m][n];
			for(int i = 0; i < n; i++) {
				st = new StringTokenizer(br.readLine());
				for(int j = 0; j < m; j++) {
					arrt[j][i] = Integer.parseInt(st.nextToken());
				}
			}
			Column[] cols = new Column[m];
			for(int j = 0; j < m; j++) {
				cols[j] = new Column(arrt[j]);
			}
			Arrays.sort(cols, Collections.reverseOrder());
			m = Integer.min(n, m);
			int[][] arr = new int[n][m];
			for(int i = 0; i < n; i++) {
				for(int j = 0; j < m; j++) {
					arr[i][j] = cols[j].arr[i];
				}
			}
			int[][] max = new int[m][reps[n].size()];
			for(int c = 0; c < m; c++) {
				for(int mask = 0; mask < (1 << n); mask++) {
					int curr = 0;
					for(int i = 0; i < n; i++) {
						if((mask & (1 << i)) > 0) curr += arr[i][c];
					}
					int cl = eqcl[n][mask];
					max[c][cl] = Integer.max(max[c][cl], curr);
				}
			}
			int[][] dp = new int[m+1][reps[n].size()];
			for(int c = 0; c < m; c++) {
				for(int i = 0; i < reps[n].size(); i++) {
					int mask = reps[n].get(i);
					for(int next: nexts[n][i]) { //opt
						int cl = eqcl[n][next];
						int dl = eqcl[n][mask | next];
						if(dp[c][i] + max[c][cl] > dp[c+1][dl]) { // el dp
							dp[c+1][dl] = dp[c][i] + max[c][cl];
						}
					}
				}
			}
			bw.write(dp[m][reps[n].size() - 1]+"\n");
		}
		bw.flush();
	}
	static int rot(int x, int k, int n) {
		int a = x << k;
		int b = x >> (n - k);
		return (a + b) & ((1 << n) - 1);
	}
	static class Column implements Comparable<Column>{
		int[] arr;
		int max;
		public Column(int[] arr) {
			this.arr = arr;
			max = 0;
			for(int k: arr) {
				max = Integer.max(max, k);
			}
		}
		@Override
		public int compareTo(Column col) {
			return max - col.max;
		}
	}
}


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

/*
6
2 2
5 2
1 5
1 1
3
1 2
1 1
1 2
1 1
1 2
2 3
2 1
1
1

*/

public class e2 {

	static int n;
	static int m;
	static int[][] mat;

	public static void main(String[] args){
		JS scan = new JS();
		PrintWriter out = new PrintWriter(System.out);
		int t = scan.nextInt();
		long start = System.currentTimeMillis();
		for(int q = 1; q <= t; q++){
			n = scan.nextInt();
			m = scan.nextInt();
			// n = 12;
			// m = 20000;
			mat = new int[n][m];
			for(int i = 0; i < n; i++){
				for(int j = 0; j < m; j++){
					mat[i][j] = scan.nextInt();
					// mat[i][j] = 100000;
				}
			}
			int[] max = new int[m];
			PriorityQueue<Item> pq = new PriorityQueue<Item>();
			for(int i = 0; i < m; i++){
				for(int j = 0; j < n; j++){
					max[i] = max(max[i], mat[j][i]);
				}
				pq.add(new Item(i, max[i]));
			}
			ArrayList<Item> guys = new ArrayList<Item>();
			while(!pq.isEmpty() && guys.size() < n){
				Item tt = pq.poll();
				guys.add(tt);
			}

			int[][] cost = new int[guys.size()][1 << n];
			// long time = System.currentTimeMillis();
			for(int i = 0; i < guys.size(); i++){
				int g = guys.get(i).a;
				for(int s = 0; s < n; s++){
					for(int j = 0; j < (1 << n); j++){
						int sum = 0;
						for(int k = 0; k < n; k++){
							if((j & (1 << k)) > 0){
								sum += mat[(k+s)%n][g];
							}
						}
						cost[i][j] = max(cost[i][j], sum);
					}
				}
			}

			// for(int i = 0; i < guys.size(); i++) System.out.println(Arrays.toString(cost[i]));

			// System.out.println(System.currentTimeMillis()-time);
			int full = (1 << n)-1;
			// time = System.currentTimeMillis();
			int[][] dp = new int[guys.size()+1][1 << n];
			int ans = 0;

			for(int c = 0; c < guys.size(); c++){
					for(int j = 0; j < (1 << n); j++){
						for(int i = j; i < (1 << n); i = (i+1)|j){
							dp[c+1][i] =
								max(dp[c+1][i], cost[c][j]+dp[c][i^j]);

							ans = max(ans, dp[c+1][i]);
						}
					}
			}
			// for(int i = 0; i < dp.length; i++) System.out.println(Arrays.toString(dp[i]));
			// System.out.println(System.currentTimeMillis()-time);

			out.println(ans);
		}
		// System.out.println(System.currentTimeMillis()-start);
		out.flush();
	}

	static int max(int a, int b){
		return a > b? a : b;
	}

	static class Item implements Comparable<Item>{

		int a;
		int b;

		public Item(int a, int b){
			this.a = a;
			this.b = b;
		}

		public int compareTo(Item o){
			return o.b-this.b;
		}
	}

	static class JS{
		public int BS = 1<<16;
		public char NC = (char)0;
		byte[] buf = new byte[BS];
		int bId = 0, size = 0;
		char c = NC;
		double num = 1;
		BufferedInputStream in;

		public JS() {
			in = new BufferedInputStream(System.in, BS);
		}

		public JS(String s) throws FileNotFoundException {
			in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
		}

		public char nextChar(){
			while(bId==size) {
				try {
					size = in.read(buf);
				}catch(Exception e) {
					return NC;
				}
				if(size==-1)return NC;
				bId=0;
			}
			return (char)buf[bId++];
		}

		public int nextInt() {
			return (int)nextLong();
		}

		public long nextLong() {
			num=1;
			boolean neg = false;
			if(c==NC)c=nextChar();
			for(;(c<'0' || c>'9'); c = nextChar()) {
				if(c=='-')neg=true;
			}
			long res = 0;
			for(; c>='0' && c <='9'; c=nextChar()) {
				res = (res<<3)+(res<<1)+c-'0';
				num*=10;
			}
			return neg?-res:res;
		}

		public double nextDouble() {
			double cur = nextLong();
			return c!='.' ? cur:cur+nextLong()/num;
		}

		public String next() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c>32) {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public String nextLine() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c!='\n') {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public boolean hasNext() {
			if(c>32)return true;
			while(true) {
				c=nextChar();
				if(c==NC)return false;
				else if(c>32)return true;
			}
		}
	}
}


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

public class TaskE {

    static int[][] transpose(int[][] a, int n, int m) {
        int[][] t = new int[m][n];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                t[j][i] = a[i][j];
            }
        }

        return t;
    }

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

        int t = in.nextInt();

        while (t-- > 0) {
            int n = in.nextInt();
            int m = in.nextInt();

            int[][] a = new int[n + 1][m];

            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    a[i][j] = in.nextInt();
                    a[n][j] = Math.max(a[n][j], a[i][j]);
                }
            }

            a = transpose(a, n, m);

            Arrays.sort(a, new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    int max1 = 0;
                    for (int i = 0; i < o1.length; i++) {
                        max1 = Math.max(max1, o1[i]);
                    }

                    int max2 = 0;
                    for (int i = 0; i < o2.length; i++) {
                        max2 = Math.max(max2, o2[i]);
                    }

                    return max2 - max1;
                }
            });

            a = transpose(a, m, n);

            int[] dp = new int[1 << n];

            for (int i = 0; i < Math.min(n, m); i++) {
                int[] best = new int[1 << n];

                for (int j = 1; j < (1 << n); j++) {
                    for (int k = 0; k < n; k++) {
                        int sum = 0;
                        for (int l = 0; l < n; l++) {
                            if ((j & (1 << l)) != 0)
                                sum += a[(l + k) % n][i];
                        }
                        best[j] = Math.max(best[j], sum);
                    }
                }

                int[] dp1 = dp.clone();

                for (int j = 0; j < (1 << n); j++) {
                    for (int k = j; k > 0; k = (k - 1) & j) {
                        dp[j] = Math.max(dp[j], dp1[k ^ j] + best[k]);
                    }
                }
            }

            out.println(dp[(1 << n) - 1]);
        }

        out.close();
    }

    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        FastReader(InputStream is) {
            br = new BufferedReader(new InputStreamReader(is));
        }

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

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

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

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                st = new StringTokenizer(nextLine());
            }
            return st.nextToken();
        }

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