序列

序列

给出m个长度为n的序列,第i个序列为({a[i][j]}),现在从m个序列中分别各自取出一个数,求这些数的和的前n小值,(0<m≤1000,0<n≤2000)

显然需要对每个序列进行从小到大排序,于是对于两个序列({a_i},{b_i})研究,显然最小值为(a_1+b_1),而次小值的决策集合容易知道为(a_2+b_1,a_1+b_2),如果确定了次小值的决策为(a_2+b_1),那么次次小值的决策集合增加了(a_3+b_1,a_2+b_2),于是发现对于当前决策了({a_i,b_j}),就需要删掉该个决策增加决策(a_{i+1},b_j or a_i,b_{j+1})

显然这样会决策出现重复,没人愿意花空间去开check数组,于是发现这个问题(i,j+1,i+1,j),就类似与网格图上从左上角出发,每次只能向下走或者向右走,因此我们只要如果一个决策的(j!=1)的话,就不允许它i增加,这样正好不重不漏,问题在于有些决策暂时没有入集合,会照成影响吗?

比如(a_i,b_j),其中j不为1,显然选择它后只会增加决策(a_i,b_{j+1}),而不会增加决策(a_{i+1},b_j),但是决策(a_{i+1},b_j)会不会影响到以后的最优?注意到此时(a_{i+1},b_{j-1})要么没入集合,要么不是最优,显然(a_{i+1},b_{j-1})要比(a_{i+1},b_j)优秀,既然它都不够优秀,何况(a_{i+1},b_j)呢。

于是我们只要开一个二元组({i,j}),比较关键字为(a_i+b_j),全部加入小根堆,便于很快地求出最小值,然后推广到多个序列,我们只要把之前的求出了前n小值作为({a_i},{b_i})的合并后的序列,然后与第三个序列进行同样的操作即可,最终时间复杂度(O(nmlog(n)))

仔细思考一下,会发现这道题目是最优性贪心+合并性贪心,而且还涉及到对于决策集合的研究,所以自然也就很困难了。

我感受到了我的弱小。

参考代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#define il inline
#define ri register
#define Size 2500
using namespace std;
int a[Size],b[Size],c[Size];
template<class free>
struct small{
	free a[Size*2];int n;
	il void push(free x){
		a[++n]=x;int p(n);
		while(p>1)
			if(a[p]<a[p>>1])
				swap(a[p],a[p>>1]),
					p>>=1;
			else break;
	}
	il void pop(){
		a[1]=a[n--];int p(1),s(2);
		while(s<=n){
			if(s<n&&a[s+1]<a[s])++s;
			if(a[s]<a[p])
				swap(a[s],a[p]),p=s,s=p<<1;
			else break;
		}
	}
};
struct er{
	int i,j;
	il bool operator<(const er&x)const{
		return a[i]+b[j]<a[x.i]+b[x.j];
	}
};int n;
small<er>T;il void merge();
int main(){int lsy;scanf("%d",&lsy);
	while(lsy--){
		int m;scanf("%d%d",&m,&n);
		for(int i(1);i<=n;++i)scanf("%d",&b[i]);
		sort(b+1,b+n+1);
		for(int i(1),j;i<m;++i){
			for(j=1;j<=n;++j)scanf("%d",&a[j]);
			sort(a+1,a+n+1),merge();
			for(j=1;j<=n;++j)b[j]=c[j];
		}for(int i(1);i<=n;++i)
			 printf("%d ",b[i]);
		putchar('
');
	}
	return 0;
}
il void merge(){
	T.n=0,T.push({1,1});
	for(int i(1),x,y;i<=n;++i){
		x=T.a[1].i,y=T.a[1].j;
		if(y<n)T.push({x,y+1});
		if(y==1&&x<n)T.push({x+1,y});
		c[i]=a[x]+b[y],T.pop();
	}
}

原文地址:https://www.cnblogs.com/a1b3c7d9/p/11248237.html