• P1631序列合并


    题目链接

    题意:

    ​ 有两个长度都为N(1<=N<=100000)的序列A和B,在A和B中各取一个数相加可以得到N2个和,求这N2个和中最小的N个。

    思路:

    ​ 首先会想到暴力,O(N^2),一看范围十万,肯定受不了。

    ​ 再考虑贪心,以两个队列的头相加,进入前n小的和中,然后选择两头中较大的元素弹出,以此类推,但我发现一个问题:虽然这样所找出的元素满足单调递增,但每个被弹出的元素在弹出后就不用了,将会导致的情况我用一个样例来表示:

    5
    2 4 9 10 11
    1 1 1 1 1
    

    答案显然是3 3 3 3 3,然而贪心给出的是3 5 10 11 11。

    ​ 考虑记忆化搜索和dp,但记忆化的f存什么呢?存第n个最小的和吗?但我们还不知道第n小的和的值,存当前已知的数值吗?显然不行。dp似乎行得通,dp通常用于最优性问题,但我没想出来。

    ​ 我发现题目中有:Ai<=A{i+1},Bi<=B{i+!}。那么可以得出:

    [A_i+B_ile A_{i+1}+B_i,A_i+B_{i+1} ]

    ​ 所以每得到一个和n=Ai+Bi,那么就将Ai+1和Bi的和与Ai和Bi+1的和放入某个容器,而这个容器中的最小者定为下一个最小的(想想为什么?)。

    ​ 那么既然是堆的题,又是求最小者,那么这个容器的最佳候选者应当是小根堆,堆的插入、删除操作都只有O(log2(n))的复杂度,要找n个最小和,就是O(nlog2(n))的复杂度,可以承受。

    100分AC代码
    #include <bits/stdc++.h>
    using namespace std;
    int n,cnt=0;
    int a[100005];
    int b[100005];
    struct node{
    	int a;
    	int b;
    	int num;
    }heap[200005];
    map<int,map<int,int> > mapp;//防止重复计算相当于bool b[ai][bi],但这样会爆
    void upd(int now){
    	if(now>cnt)return ;
    	int j=now*2;
    	if(heap[j].num>heap[j+1].num){
    		j+=1;
    	}
    	if(heap[j].num<heap[now].num&&j<=cnt){
    		swap(heap[now],heap[j]);
    		upd(j);
    	}
    	return ;
    }
    void deltop(){
    	heap[1].num=heap[cnt].num;
    	heap[1].a=heap[cnt].a;
    	heap[1].b=heap[cnt].b;
    	cnt--;
    	upd(1);
    }
    void dwd(int now){
    	if(now==1)return ;
    	int f=now>>1;
    	if(heap[f].num>heap[now].num){
    		swap(heap[f],heap[now]);
    		dwd(f);
    	}
    	return ;
    }
    int main() {
    	cin>>n;
    	for(int i=1;i<=n;i++)cin>>a[i];
    	for(int i=1;i<=n;i++)cin>>b[i];
    	heap[++cnt].num=a[1]+b[1];
    	heap[cnt].a=1;
    	heap[cnt].b=1;
    	mapp[1][1]=1;
    	for(int t=1;t<=n;t++){
    		cout<<heap[1].num<<' ';
    		int aa=heap[1].a,bb=heap[1].b;
    		if(!mapp[aa+1][bb]){
    			mapp[aa+1][bb]=1;
    			++cnt;
    			heap[cnt].num=a[aa+1]+b[bb];
    			heap[cnt].a=aa+1;
    			heap[cnt].b=bb;
    			dwd(cnt);
    		}
    		if(!mapp[aa][bb+1]){
    			mapp[aa][bb+1]=1;
    			++cnt;
    			heap[cnt].num=a[aa]+b[bb+1];
    			heap[cnt].a=aa;
    			heap[cnt].b=bb+1;
    			dwd(cnt);
    		}
    		deltop();
    	}
    	return 0;
    }
    

    大功告成!

  • 相关阅读:
    Angular Universal教学-将现有专案导入Server Side Render
    [.NET] 使用ValidationContext快速进行模型资料的验证
    FINS/TCP_OMRON(1)
    C#中字段、属性、只读、构造函数赋值、反射赋值的相关
    async异步方法
    C# GetHashCode、Equals函数和键值对集合的关系
    JS三个编码函数和net编码System.Web.HttpUtility.UrlEncode比较
    ES6摘抄
    js基础
    js自执行函数、调用递归函数、圆括号运算符、函数声明的提升
  • 原文地址:https://www.cnblogs.com/returnG/p/13143685.html
Copyright © 2020-2023  润新知