用到的思想:分组思想
首先考虑只有两个序列的情况
a1 a2 a3 ...... an
b1 b2 b3 ...... bn
ps : a 数组是提前排序的 从小到大
把所有的情况枚举出来
b1+a1, b1+a2, b1+a3,.... b1 + an
b2+a1, b2+a2, b2+a3,.... b2 + an
.................................
bn+a1, bn+a2, bn+a3..... bn + an
第一步 选出最小的数 毫无疑问 最小的是在第一列当中,选出来之后,再选第二小将选中的那个数后面的那个数加入到选择方案中
比如 第一步我们选择的是 b2+a1 那么 在第二步选择第二小的数的时候,就应该把第一列的数 除去 b2+a1 再把b2 + a2 放入选择的所有情况中 再选出最小的数 以此类推 选出在这两个序列中 前 n 小 的数 作为一个新的序列
然后再以此类推将a数组(更新完的操作)与下一个序列进行上一步选择,总共进行m - 1 次操作
PII 第一个存数字 第二个存当前所在下标

#include<bits/stdc++.h>
#define pr printf
#define sc scanf
#define fur(i,a,b) for(int i = a; i<= b ;i++)
#define fdr(i,a,b) for(int i = a ;i>=b ;i--)
using namespace std;
const int N = 2000 + 10 ;
int a[N],b[N],c[N];
typedef long long ll;
typedef pair<int,int> PII;
int n,m;
void work()
{
    priority_queue<PII, vector <PII> ,greater <PII> > q;
    for(int i = 0 ;i < n ; i++){
        q.push({ a[0] + b [i] , 0 } );
    }
    for(int i = 0 ;i < n ; i++){
        PII t = q.top();
        q.pop();
        int s = t.first ;
        int p = t.second ;
        q.push( {s - a[p] + a[p + 1 ], p + 1 } );
        c[i] = s;
    }
    for(int i = 0 ;i < n ; i+= 1) a[i] = c[i] ;

}
int main()
{
    //freopen("in.txt","r",stdin);
    // m 个序列 每个序列 n 个数
    int T ;
    sc("%d",&T);
    while(T--){
        sc("%d%d",&m ,&n);
        for(int i = 0 ;i < n; i++){
            sc("%d",&a[i]);
        }
        sort(a,a+n);
        for(int i = 0 ; i < m -1 ;i ++){
            for(int j = 0 ; j < n ;j ++){
                sc("%d",&b[j]);
            }
            work();
        }
        for(int i  = 0 ; i< n ; i++){
            pr("%d ",a[i]);
        }
        puts("");
    }
    return 0;
}