题意简述
给定\(M\)个长度为\(N\)的序列,从每个序列中任取一个数求和,求前\(N\)小和。
数据范围见题
简单口胡
-
\(M = 1\)
把原序列排个序输出完事。 -
\(M = 2\)
我们将两个序列分别假设为\(a,b\),并已经将其排好序。
定义:
- 第\(k\)小和为\(F(k)\)
- 若\(a_i + b_j\)可能是\(F(k)\)的答案,我们称二元组\((i,j)\)为\(F(k)\)的候选二元组。
- 若\(a_i + b_j\)是\(F(k)\)的答案,我们称二元组\((i,j)\)为\(F(k)\)的答案二元组。
Solution:
首先\(F(1)\)的答案二元组显然为\((1,1)\)。
考虑\(F(2)\)的候选二元组,有\((1,2),(2,1)\),这些都有可能。
假设\(F(2)\)的答案二元组为\((2,1)\),那么\(F(3)\)的候选二元组即为\((1,2),(2,2),(3,1)\)。
我们会发现,如果\((x,y)\)是\(F(k)\)的答案二元组,那么\((x + 1,y)\)和\((x,y + 1)\)就是\(F(k + 1)\)的候选二元组。
原因:\(a_{x + 1}\)是在\(a\)中比\(a_{x}\)大的最小的数,也就是说排名有可能只会\(+1\),\(b_{y + 1}\)和\(b_y\)同理,所以它们是候选二元组。
- \(M > 2\)
用优先队列维护一下,每次先处理前面两排,然后将答案合并再与下一排进行计算。
但是我们会发现有时同时更新出\((x + 1,y)\)和\((x,y + 1)\)会更新出相同的二元组。
原因:设\(F(k)\)的答案二元组为\((x_0,y_0)\)
那么\(F(k + 1)\)的候选二元组就包含\((x_0 + 1,y_0),(x_0,y_0 + 1)\)
若\(F(k_0)(k_0 > k)\)的答案二元组为\((x_0 + 1,y_0)\),那么其会整出\((x_0 + 2,y_0),(x_0 + 1,y_0 + 1)\)
若\(F(k_1)(k_1 > k)\)的答案二元组为\((x_0,y_0 + 1)\),那么其会整出\((x_0,y_0 + 2),(x_0 + 1,y_0 + 1)\),与上面的\((x_0 + 1,y_0 + 1)\)冲突。
这里你可以用map / hash 判断,也可以用《算法竞赛进阶指南》上的方法,这里不叙述,也可以看代码。
# include <bits/stdc++.h>
using namespace std;
int t;
int m,n;
const int M = 1005,N = 2005;
int a[M][N];
int nowi,nowj;
int A[N]; // cun chu
struct node
{
int x,y;
bool flag; // flag = 0 -> y + 1 flag = 1 -> x + 1;
node() {}
node(int _x,int _y,bool f) : x(_x),y(_y),flag(f) {}
};
bool operator < (const struct node &x,const struct node &y)
{
return a[nowi][x.x] + a[nowj][x.y] > a[nowi][y.x] + a[nowj][y.y];
}
priority_queue <node> q;
void solve(void)
{
while(!q.empty()) q.pop();
q.push(node(1,1,0));
int tot = 0;
while(tot < n)
{
node X = q.top();q.pop();
q.push(node(X.x,X.y + 1,1));
if(X.flag == 0) q.push(node(X.x + 1,X.y,0));
A[++tot] = a[nowi][X.x] + a[nowj][X.y];
}
for(int i = 1; i <= n; i++) a[nowj][i] = A[i];
return;
}
int main(void)
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&m,&n);
for(int i = 1; i <= m; i++)
{
for(int j = 1; j <= n; j++)
{
scanf("%d",&a[i][j]);
}
sort(a[i] + 1,a[i] + n + 1);
}
if(m == 1)
{
for(int i = 1; i <= n; i++)
{
printf("%d ",a[1][i]);
}
putchar(‘\n‘);
continue;
}
nowi = 1,nowj = 2;
while(nowj <= m)
{
solve();
++nowi,++nowj;
}
for(int i = 1; i <= n; i++)
{
printf("%d ",a[m][i]);
}
putchar(‘\n‘);
}
return 0;
}
//Sequence luyiming123