>Link
ybtoj序列合并
luogu P1631
>解题思路
A和B是已经从小到大排好序的,但是如果将所有
N
2
N^2
N2个和放进堆再一个个推出堆顶,显然是不行的
我们发现如下规律:
A
1
+
B
1
≤
A
1
+
B
2
≤
…
≤
A
1
+
B
N
A_1+B_1≤A_1+B_2≤…≤A_1+B_N
A1+B1≤A1+B2≤…≤A1+BN
A
2
+
B
1
≤
A
2
+
B
2
≤
…
≤
A
2
+
B
N
A_2+B_1≤A_2+B_2≤…≤A_2+B_N
A2+B1≤A2+B2≤…≤A2+BN
…
…
…
…
…………
…………
A
N
+
B
1
≤
A
N
+
B
2
≤
…
≤
A
N
+
B
N
A_N+B_1≤A_N+B_2≤…≤A_N+B_N
AN+B1≤AN+B2≤…≤AN+BN
所以我们把每一行最前面的那个和放入堆,每次取出堆顶的数,再把取出的那个数 后面的数放入堆代替它,直到取完N个数
既然有上面的规律,那么也同时有:
B
1
+
A
1
≤
B
1
+
A
2
≤
…
≤
B
1
+
A
N
B_1+A_1≤B_1+A_2≤…≤B_1+A_N
B1+A1≤B1+A2≤…≤B1+AN
B
2
+
A
1
≤
B
2
+
A
2
≤
…
≤
B
2
+
A
N
B_2+A_1≤B_2+A_2≤…≤B_2+A_N
B2+A1≤B2+A2≤…≤B2+AN
…
…
…
…
…………
…………
B
N
+
A
1
≤
B
N
+
A
2
≤
…
≤
B
N
+
A
N
B_N+A_1≤B_N+A_2≤…≤B_N+A_N
BN+A1≤BN+A2≤…≤BN+AN
为什么“只考虑”上面的规律?
其实通过观察发现,上面的规律包含了下面的,上面的第一行对应的就是下面的第一列,
在上面的规律中,第一行第二个数有可能比其他行的第一个数还要小,但是这不影响结果。因为
A
1
+
B
2
A_1+B_2
A1+B2一定比
A
1
+
B
1
A_1+B_1
A1+B1大,当
A
1
+
B
1
A_1+B_1
A1+B1还没选的时候就一定优先选择它,
A
1
+
B
2
A_1+B_2
A1+B2在不在堆中无所谓;而当
A
1
+
B
1
A_1+B_1
A1+B1选择了以后,
A
1
+
B
2
A_1+B_2
A1+B2就会进堆,与“其他行的第一个数”“竞争”
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 100010
using namespace std;
struct node
{
int x, y, sum;
bool operator <(const node &xx) const
{return xx.sum < sum;}
};
std::priority_queue<node> H;
int n, a[N], b[N];
int main()
{
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]);
for (int i = 1; i <= n; i++)
H.push ((node){i, 1, a[i] + b[1]});
for (int i = 1; i <= n; i++)
{
printf ("%d ", H.top().sum);
node k = H.top();
H.pop();
H.push ((node){k.x, k.y + 1, a[k.x] + b[k.y + 1]});
}
return 0;
}