牛客 Sequence
https://ac.nowcoder.com/acm/contest/1011/B
题面
给定M个长度为N的序列,从每个序列中任取一个数求和,可以构成\(N^M\)个和,求最小的N个和
\(N\leq 2000,M\leq 100\)
分析
显然合并\(N\)个是\(N^M\)的
可以先考虑合并2个
对于两个数列\({a_n},{b_n}\)
可以有
\[ \left[
\begin{matrix}
a_1+b_1 & a_1+b_2 & a_1+b_3 & \ldots\\
a_2+b_1 & a_2+b_2 & a_2+b_3 & \ldots\\
a_3+b_1 & a_3+b_2 & a_3+b_3 & \ldots
\end{matrix}
\right]
\]
每一行都是单调增
所以只需要将每一行第一个加入堆中,\(O(lgn)\)维护,取出前N小和即可
合并N个可以先合并2个,再合并2个,\(\ldots\)
#include<bits/stdc++.h>
using namespace std;
const int N=2006;
int n,m,a[N],b[N];
struct A{int x, y; };
bool operator >(A i,A j) {
return i.x>j.x;
}
priority_queue<A,vector<A>,greater<A> >q;
int main() {
int T; scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) {
scanf("%d",&a[i]);
}
sort(a+1,a+m+1);
for(int i=1;i<=m;i++) b[i]=a[i];
for(int i=2;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf("%d",&a[j]);
}
sort(a+1,a+m+1);
for(int j=1;j<=m;j++) {
q.push((A){b[j]+a[1],1});
}
for(int j=1;j<=m;j++) {
A u=q.top(); q.pop();
b[j]=u.x;
q.push((A){u.x-a[u.y]+a[u.y+1],u.y+1});
}
for(int j=1;j<=m;j++) q.pop();
}
for(int i=1;i<=m;i++) {
printf("%d%c",b[i],i==m?'\n':' ');
}
}
return 0;
}

浙公网安备 33010602011771号