关于此题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;
}

浙公网安备 33010602011771号