图片加载可能有点慢,请跳过题面先看题解,谢谢

我们先考虑两个序列的情况(以下这一段蒯自 刘汝佳训练指南):
这个问题可以转换成一个多路归并问题,有这样一个含有 \(n^2\) 个元素的表:
- \(A[1]+B[1]\leq A[1]+B[2]\leq A[1]+B[3]\leq\) ...
- \(A[2]+B[1]\leq A[2]+B[2]\leq A[2]+B[3]\leq\) ...
- \(A[3]+B[1]\leq A[3]+B[2]\leq A[3]+B[3]\leq\) ...
- ......
这里用优先队列维护一个二元组 \((s,b)\) ,其中,\(s=A[a]+B[b]\),\(s\) 最小的放堆顶
每次从堆中取出一个 \((s,b)\) 后,将 \((s',b+1)\) 丢入堆中,直到取出了 \(n\) 个最小值
但是我们在维护 \((s,b)\) 这个二元组时并没有记录 \(a\) 的值,那则么样才能得到 \((s',b+1)\) 呢
很简单, \(s'=s-B[b]+B[b+1]\),根本不需要知道 \(a\) 。
$
$
这道题将上面那个两个序列的情况进行了推广
其实就相当于每次拿一个序列去跟 \(A序列\) 进行上面那个操作,然后用答案覆盖 \(A\),直到所有序列都操作过一次
//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<algorithm>
#define il inline
#define RG register
using namespace std;
il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }
int n,a[1010][1010];
struct node{int s,x;
il bool operator<(const node &c)const{return s>c.s;}
};
priority_queue<node>q;
il void init(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
a[i][j]=gi();
sort(a[i]+1,a[i]+n+1);
}
}
il void work(){
for(int i=2;i<=n;i++){
for(int j=1;j<=n;j++)
q.push((node){a[1][j]+a[i][1],1});
for(int j=1;j<=n;j++){
node x=q.top(); q.pop();
a[1][j]=x.s; int b=x.x;
if(b<n) q.push((node){x.s-a[i][b]+a[i][b+1],b+1});
}
while(!q.empty()) q.pop();
}
printf("%d",a[1][1]); for(int i=2;i<=n;i++) printf(" %d",a[1][i]);
puts("");
}
int main(){ while(scanf("%d",&n)!=EOF){ init(); work(); } return 0; }
本文介绍了一种解决多个有序序列寻找前n个最小值和的高效算法。通过使用优先队列维护二元组,每次迭代更新最小值,并通过代码实现展示了如何处理多个序列的数据结构操作。
568

被折叠的 条评论
为什么被折叠?



