题意:传送门
给出m个序列,一个序列中有n个数,每次从m个序列中各取一个数构成和,最后输出前n个最小的和。
题解:考虑两个序列,设为序列a和b,可以将a序列排序,那么所有的选取方式为
b
[
0
]
+
a
[
0
]
,
b
[
0
]
+
a
[
1
]
,
b
[
0
]
+
a
[
2
]
,
+
⋯
 
,
+
b
[
0
]
+
a
[
n
]
b[0]+a[0],b[0]+a[1],b[0]+a[2],+\cdots,+b[0]+a[n]
b[0]+a[0],b[0]+a[1],b[0]+a[2],+⋯,+b[0]+a[n]
b
[
1
]
+
a
[
0
]
,
b
[
1
]
+
a
[
1
]
,
b
[
1
]
+
a
[
2
]
,
+
⋯
 
,
+
b
[
1
]
+
a
[
n
]
b[1]+a[0],b[1]+a[1],b[1]+a[2],+\cdots,+b[1]+a[n]
b[1]+a[0],b[1]+a[1],b[1]+a[2],+⋯,+b[1]+a[n]
b
[
2
]
+
a
[
0
]
,
b
[
2
]
+
a
[
1
]
,
b
[
2
]
+
a
[
2
]
,
+
⋯
 
,
+
b
[
2
]
+
a
[
n
]
b[2]+a[0],b[2]+a[1],b[2]+a[2],+\cdots,+b[2]+a[n]
b[2]+a[0],b[2]+a[1],b[2]+a[2],+⋯,+b[2]+a[n]
⋯
\cdots
⋯
b
[
n
]
+
a
[
0
]
,
b
[
n
]
+
a
[
1
]
,
b
[
n
]
+
a
[
2
]
,
+
⋯
 
,
+
b
[
n
]
+
a
[
n
]
b[n]+a[0],b[n]+a[1],b[n]+a[2],+\cdots,+b[n]+a[n]
b[n]+a[0],b[n]+a[1],b[n]+a[2],+⋯,+b[n]+a[n]
一共有
n
n
n^n
nn种选法,按照这种方式排列后,每一行都是从小到大排列的,那么每次只要从这n列种选出一个最小的,最添加进去选出去这一行的下一个,那么一共选择n次就是序列a和b合并后的前n个数的新序列,之后再合并m-1次就是最终的答案了。
c
o
d
e
:
code:
code:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
#define pii pair<int,int>
using namespace std;
const int N=2000+5;
int T,m,n,a[N],b[N],c[N];
void merge()
{
priority_queue<pii,vector<pii>,greater<pii> >heap;
for(int i=0;i<n;i++)heap.push(make_pair(b[i]+a[0],0));
for(int i=0;i<n;i++){
int v=heap.top().first,p=heap.top().second;
c[i]=v;
heap.pop();
heap.push(make_pair(v-a[p]+a[p+1],p+1));
}
for(int i=0;i<n;i++)a[i]=c[i];
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++)scanf("%d",&a[i]);
sort(a,a+n);
for(int i=0;i<m-1;i++){
for(int j=0;j<n;j++)scanf("%d",&b[j]);
merge();
}
for(int i=0;i<n;i++)printf("%d ",a[i]);
printf("\n");
}
return 0;
}