题目:POJ2442.
题目大意:给定
m
m
m个长度为
n
n
n的序列,要求在每一个序列中取出一个数并求和,总共会得到
n
m
n^m
nm个和,现在要求这之中最小的
n
n
n个.
1
≤
n
≤
2
∗
1
0
3
,
1
≤
m
≤
100
1\leq n\leq 2*10^3,1\leq m\leq 100
1≤n≤2∗103,1≤m≤100.
首先先考虑 m = 2 m=2 m=2怎么做.
对于两个序列,我们把这两个序列分别从小到大排序.设排序后两个序列为 a , b a,b a,b,贪心地想到若 k k k小和为 a [ i ] + b [ j ] a[i]+b[j] a[i]+b[j], k + 1 k+1 k+1小和的候选答案中就加入了 a [ i + 1 ] + b [ j ] a[i+1]+b[j] a[i+1]+b[j]和 a [ i ] + b [ j + 1 ] a[i]+b[j+1] a[i]+b[j+1].
有了这个性质后,我们用一个小根堆来维护一个二元组 ( i , j ) (i,j) (i,j)表示一个候选答案为 a [ i ] + b [ j ] a[i]+b[j] a[i]+b[j],然后每次把堆顶取出后加入 ( i + 1 , j ) (i+1,j) (i+1,j)和 ( i , j + 1 ) (i,j+1) (i,j+1)两个候选答案.容易发现取出前 n n n小的候选答案集合大小不会超过 O ( n ) O(n) O(n),因此复杂度是 O ( n log n ) O(n\log n) O(nlogn)的.
值得注意的是, ( i , j ) (i,j) (i,j)可以通过 ( i − 1 , j ) (i-1,j) (i−1,j)和 ( i , j − 1 ) (i,j-1) (i,j−1)两个答案加入候选集合.为了避免重复,我们钦定对于每一个候选答案 ( i , j ) (i,j) (i,j),若 j j j指针发生了移动则 i i i指针不会再发生移动,这样就可以保证不会重复了.
具体实现的时候我们可以维护一个四元组 ( x , i , j , t a g ) (x,i,j,tag) (x,i,j,tag),其中 x = a [ i ] + b [ j ] x=a[i]+b[j] x=a[i]+b[j]表示一个候选答案, t a g = 0 / 1 tag=0/1 tag=0/1表示 j j j指针移动 / / /没有移动过.
而对于 m > 2 m>2 m>2的情况,我们可以直接把前两个序列得到的 n n n小值作为一个序列,继续与第 3 3 3个序列计算 n n n小值并以此类推…时间复杂度 O ( m n log n ) O(mn\log n) O(mnlogn).
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int M=100,N=2000;
struct state{
int x,i,j,tag;
state(int X=0,int I=0,int J=0,int Tag=0){x=X;i=I;j=J;tag=Tag;}
bool operator > (const state &p)const{return x>p.x;}
};
priority_queue<state,vector<state>,greater<state> >q;
int a[M+9][N+9],n,m,tmp[N+9];
Abigail into(){
scanf("%d%d",&m,&n);
for (int i=1;i<=m;++i)
for (int j=1;j<=n;++j)
scanf("%d",&a[i][j]);
}
Abigail work(){
state t;
sort(a[1]+1,a[1]+1+n);
for (int k=2;k<=m;++k){
int i=1,j=1;
sort(a[k]+1,a[k]+1+n);
while (!q.empty()) q.pop();
q.push(state(a[1][i]+a[k][j],i,j,0));
for (int l=1;l<=n;++l){
t=q.top();q.pop();
tmp[l]=t.x;
q.push(state(a[1][t.i]+a[k][t.j+1],t.i,t.j+1,1));
if (!t.tag) q.push(state(a[1][t.i+1]+a[k][t.j],t.i+1,t.j,0));
}
for (int l=1;l<=n;++l) a[1][l]=tmp[l];
}
}
Abigail outo(){
for (int i=1;i<n;++i)
printf("%d ",a[1][i]);
printf("%d\n",a[1][n]);
}
int main(){
int T;
scanf("%d",&T);
while (T--){
into();
work();
outo();
}
return 0;
}