zoukankan      html  css  js  c++  java
  • 序列

    序列

    给出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();
    	}
    }
    
    
  • 相关阅读:
    BGP--边界网关协议
    Paris Traceroute
    网站flash黑屏问题
    org.pentaho.di.ui.core.widget.PasswordTextVar
    java 金额计算,商业计算 double不精确问题 BigDecimal,Double保留两位小数方法
    spring mvc 利用匿名内部类构建返回json对象
    bootstrap3-typeahead 自动补全
    高德地图 省市区商圈数据
    小米wifi远程提交下载任务地址
    国外HTML网站模版(卖成品模版)
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11248237.html
Copyright © 2011-2022 走看看