题意:
有两个长度为 N 的序列 A 和 B,在 A 和 B 中各任取一个数可以得到 N^2 个和,求这N^2 个和中最小的 N个。
1≤N≤100000
方法:
现将A,B从小到大排序
因为序列中A[i]+ B[j] >= A[i]+ B[j+1],A[i]+ B[j]>= A[i+1]+B[j]
所以我们只需要用优先队列记录A[i]对应哪个B[j]最小即可,当A[i]+B[j]最小时,将A[i] +B[j+1]加入到优先队列即可
错误:
首先我就想到了A[i]+ B[j] >= A[i]+ B[j+1],A[i]+ B[j]>= A[i+1]+B[j]
然后我用优先队列记录了i,j,A[i]+B[j], 如果A[I]+B[j] 最小,则将 A[i]+ B[j+1], A[i+1]+B[j] 加入到优先队列。。。
自信满满的以为一定会对。。 其实这样是错的
例如:
A[1]= 1, A[2]= 2, A[3] = 100
B[1]= 1, B[2]= 2, B[3]= 100
当A[1]+ B[1]出队,A[2]+B[1],A[1]+B[2]入队, 然后A[1]+B[2]出队,A[2]+B[2]入队,A[1]+B[2]出队,A[2]+B[2]会再次入队
所以我们记录两个数组是不行的,这样子会使得一个元素多次入队
但是如果我们将A[i]+B[1]全部入队, 然后出队sum= A[i]+b[j],只要 把sum- b[j]+ b[j+1]入队即可
因为这样保证数组A[i]在队列中只有有一个B[j]与之对应
代码:
#include <cstdio>
#include <algorithm>
#include <queue>
#define maxn 100005
using namespace std;
int a[maxn];
int b[maxn];
struct node
{
int y;
int num;
node(){}
node( int b, int c):
y(b),num(c){}
bool operator < (const node &a)const
{
return num> a.num;
}
};
priority_queue<node> q;
int main()
{
int n;
scanf("%d",&n);
for(int i= 1; i<= n; i++)
scanf("%d",&a[i]);
for(int i= 1; i<= n; i++)
scanf("%d",&b[i]);
sort(a+1, a+n+1);
sort(b+1, b+n+1);
int s= 1;
for(int i= 1; i<= n; i++)
q.push(node(1,a[i]+b[1]));
while(s<= n)
{
node N= q.top();
q.pop();
if(N.y+1<= n)
q.push(node(N.y+1, N.num- b[N.y]+ b[N.y+1]));
printf("%d ", N.num);
s++;
}
printf("\n");
return 0;
}