关于此题P1631 序列合并 的一些总结

传送门

题目大意

  • 给定两个长度为\(N\)的序列,每次选定两个\(i,j\)使得\(a[i] + b[j]\),可以合并成\(N^{2}\)个数的新序列,问此序列中最小的\(N\)个数分别是什么。

思路

  • 我们可以贪心地思考这道题。要求最大的\(N\)个数,那么我们首先对\(a\)数组和\(b\)数组进行排序,最大的肯定是\(a[1] + b[1]\),第二大的只能是\(a[1] + b[2]\)或者\(a[2] + b[1]\)。于是我们发现,可以用优先队列维护这个最大值,当目前优先队列中最大的元素是\(a[i] + b[j]\)时,我们统计答案并pop的同时,把\(a[i + 1] + b[j]\)\(a[i] + b[j + 1]\)压入优先队列,直到答案有n个为止。同时也需要注意,一个\((i,j)\)只能被算一次。

代码

#include<bits/stdc++.h>
    
using namespace std;
    
long long t;
const long long N = 2e5 + 10;
long long n,a[N],b[N],ans[N];
struct node {
    long long val,i,j;
    bool operator < (const node &a) const {
        return val > a.val;
    }
};
priority_queue<node,vector<node> > q;
unordered_map<int,int> mp[N];
    
void solve() {
    cin >> n;
    for(long long i = 1;i <= n;i++) cin >> a[i];
    for(long long i = 1;i <= n;i++) cin >> b[i];
    sort(a + 1,a + 1 + n);
    sort(b + 1,b + 1 + n);
    q.push({a[1] + b[1],1,1});
    for(long long i = 1;i <= n;i++) {
        ans[i] = q.top().val;
        long long x = q.top().i,y = q.top().j;
        q.pop();
        if(y + 1 <= n && !mp[x][y + 1])
            q.push({a[x] + b[y + 1],x,y + 1}),mp[x][y + 1] = 1;
        if(x + 1 <= n && !mp[x + 1][y])  
            q.push({a[x + 1] + b[y],x + 1,y}),mp[x + 1][y] = 1;
    }
    for(long long i = 1;i <= n;i++) cout << ans[i] << ' ';
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    t = 1;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-02-04 10:23  孤枕  阅读(8)  评论(0)    收藏  举报