import java.io.*; import java.util.*; // GPT5 Thinking public class Main { // ---- Multiset for long (TreeMap-based) ---- static class MultiSet { TreeMap mp = new TreeMap<>(); void add(long x){ mp.put(x, mp.getOrDefault(x, 0)+1); } void addAll(long[] arr){ for(long x: arr) add(x); } boolean removeOne(long x){ Integer c = mp.get(x); if(c==null) return false; if(c==1) mp.remove(x); else mp.put(x, c-1); return true; } Long pollFirst(){ var e = mp.firstEntry(); if(e==null) return null; long k = e.getKey(); removeOne(k); return k; } Long ceiling(long need){ var e = mp.ceilingEntry(need); return e==null ? null : e.getKey(); } boolean isEmpty(){ return mp.isEmpty(); } int size(){ int s=0; for(int c: mp.values()) s+=c; return s; } @Override public String toString(){ return mp.toString(); } } // 復元:成功 → 行列、失敗 → null static long[][] reconstruct(int N, long[] C) { long[][] A = new long[N][N]; if (N <= 1) { // 2x2 和が無いので全 0 で OK。C も空である必要。 return (C.length==0) ? A : null; } if (C.length != (N-1)*(N-1)) return null; // C の多重集合 MultiSet ms = new MultiSet(); for (long x : C) { if (x < 0) return null; // 非負以外は即不可能 ms.add(x); } // 上端・左端を 0 で開始(境界の自由度) // (0,0) の 2x2 和に最小値を当てる Long s00 = ms.pollFirst(); if (s00 == null) return null; // A[1][1] = s00 - (A00 + A10 + A01) = s00 A[1][1] = s00; // 1 行目の残り(i=0, j=1..N-2) // needPrefix = A[0][j] + A[1][j] (ここで A[0][j] は既決) for (int j = 1; j <= N-2; j++) { Long s = ms.pollFirst(); if (s == null) return null; long needPrefix = A[0][j] + A[1][j]; // A[0][j] は 0 起点から順に決まる // A[0][j+1] を自由に増やせるので、A[1][j+1] が非負になるよう最小に分割 long a01 = Math.max(0L, s - needPrefix); A[0][j+1] = a01; long a11 = s - needPrefix - a01; if (a11 < 0) return null; // 論理的に起こらないが保険 A[1][j+1] = a11; } // 2 行目以降を左→右、上→下に埋める for (int i = 1; i <= N-2; i++) { for (int j = 0; j <= N-2; j++) { long need = A[i][j] + A[i+1][j] + A[i][j+1]; Long s = ms.ceiling(need); if (s == null) { return null; // 満たせる 2x2 和が残っていない → 不可能 } ms.removeOne(s); A[i+1][j+1] = s - need; // 非負 } } // 使い切れていることを確認 if (!ms.isEmpty()) return null; return A; } public static void main(String[] args) throws Exception { FastScanner fs = new FastScanner(System.in); StringBuilder out = new StringBuilder(); int T = fs.nextInt(); while (T-- > 0) { int N = fs.nextInt(); int K = Math.max(0, (N-1)*(N-1)); long[] C = new long[K]; for (int i = 0; i < K; i++) C[i] = fs.nextLong(); long[][] A = reconstruct(N, C); if (A == null) { out.append("-1\n"); } else { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { if (j>0) out.append(' '); out.append(A[i][j]); } out.append('\n'); } } } System.out.print(out.toString()); } // ---- Fast Scanner ---- static class FastScanner { private final InputStream in; private final byte[] buffer = new byte[1<<16]; private int ptr=0, len=0; FastScanner(InputStream is){ in=is; } private int read() throws IOException{ if(ptr>=len){ len=in.read(buffer); ptr=0; if(len<=0) return -1; } return buffer[ptr++]; } String next() throws IOException{ StringBuilder sb=new StringBuilder(); int c; while((c=read())!=-1 && c<=32); if(c==-1) return null; do{ sb.append((char)c); } while((c=read())!=-1 && c>32); return sb.toString(); } int nextInt() throws IOException{ return Integer.parseInt(next()); } long nextLong() throws IOException{ return Long.parseLong(next()); } } }