题目
一句话题意 , 有 k 个长为 k 的序列 , 从其中每个序列选一个数 (k^k) 个和中输出前k小
考虑 有两个长为n的序列 , 从他们中选出(n)最小的和 , 可以用一个很妙的想法
在优先队列里 , 存((a_1 + b_1 , 1) , (a_2 + b_1 , 1) , (a_3 + b_1 , 1) dots)
第一个是 a+b , 第二项是b的下标 , 每次取出最小的 , 然后把 (x - b[id] + b[id] + 1) 放进去(b 是排好序的)
取 n 遍就行, 而有 k 个的序列的情况两两合并就可以了,正确性贪心可证 ,不写了。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 756;
int n;
int a[N] , b[N];
priority_queue< pair<int,int> , vector< pair<int,int> > , greater< pair<int,int> > > q;
void Merge()
{
while(q.size()) q.pop();
for(int i = 1 ; i <= n ; ++i) q.push(make_pair(a[i] + b[1] , 1));
int tot = 0;
while(q.size())
{
int x = q.top().first , y = q.top().second; q.pop();
a[++tot] = x; if(tot == n) break;
if(y < n) q.push(make_pair(x - b[y] + b[y+1] , y+1));
}
return ;
}
int main()
{
while(scanf("%d" , &n) == 1)
{
for(int i = 1 ; i <= n ; ++i) scanf("%d",&a[i]); // 这里要先读进去一遍a , 不然直接合并就是 n 个 0 与 b 合并
for(int j = 2 ; j <= n ; ++j)
{
for(int i = 1 ; i <= n ; ++i) scanf("%d",&b[i]);
sort(b + 1 , b + 1 + n);
Merge();
}
printf("%d",a[1]);
for(int i = 2 ; i <= n ; ++i) printf(" %d" , a[i]); puts("");
}
return 0;
}