洛谷 P1631 序列合并(优先队列+归并)

传送门

题目大意

给出两个序列 a , b a, b a,b,将所有的 a i + b i a_i + b_i ai+bi 求出后然后排序,只需要输出其中的前 n n n 个。

解题思路

这题的思路很巧,是利用归并的思想。

a , b a,b a,b 均排好序之后,我们在取的时候发现是有技巧的取的,如果 a i + b i a_i + b_i ai+bi 能取就肯定不会取 a i + 1 + b i a_{i+1}+ b_i ai+1+bi 或者 a i + b i + 1 a_i + b_{i +1} ai+bi+1

我么可以将其中的每 n n n 个数看做 n n n 个有序的队列:

a 1 + b 1 ≤ a 1 + b 2 ≤ . . . ≤ a 1 + b n a_1 + b_1 \leq a_1 + b2 \leq ... \leq a_1 + b_n a1+b1a1+b2...a1+bn

a 2 + b 1 ≤ a 2 + b 2 ≤ . . . ≤ a 2 + b n a_2 + b_1 \leq a_2 + b2 \leq ... \leq a_2 + b_n a2+b1a2+b2...a2+bn

a 3 + b 1 ≤ a 3 + b 2 ≤ . . . ≤ a 3 + b n a_3 + b_1 \leq a_3 + b2 \leq ... \leq a_3 + b_n a3+b1a3+b2...a3+bn

a n + b 1 ≤ a n + b 2 ≤ . . . ≤ a n + b n a_n + b_1 \leq a_n + b2 \leq ... \leq a_n + b_n an+b1an+b2...an+bn

根据归并的思想,我们只需要给每个序列一个指针,然后取 n n n 个队列中的最小值,这个最小值可以用优先队列维护,这样就能在时间复杂度之内取出前 n n n 个数了。

#include <bits/stdc++.h>

using namespace std;
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
const double eps = 1e-4;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int maxn = 1e6 + 10;

int n;
int a[maxn], b[maxn];

struct node {
    int i, j, val;

    bool operator<(const node &p) const {
        return val > p.val;
    }
};

priority_queue<node> q;

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    //ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    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 + 1 + n);
    sort(b + 1, b + 1 + n);
    for (int i = 1; i <= n; i++) q.push({i, 1, a[i] + b[1]});
    int m = n;
    bool flag = 0;
    while (m--) {
        node cur = q.top();
        q.pop();
        printf("%d ", cur.val);
        q.push({cur.i, cur.j + 1, a[cur.i] + b[cur.j + 1]});
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值