zoukankan      html  css  js  c++  java
  • HUSTOJ 有序表的最小和

    一次奇怪的AC经历。。。上周被这道题卡了3天。。。

    传送门:http://oj.gdsyzx.edu.cn/problem.php?id=1475

    题目描述

    给出两个长度为n的有序表A和B,在A和B中各任取一个元素,可以得到n2个和,求这些和中最小的n个。(不要去重)

    输入

    第一行包含一个整数n(n<=400000); 第二行与第三行分别有n个整数,分别代表有序表A和B。整数之间由一个空格隔开,大小在长整型范围内,保证有序表的数据单调递增。

    输出

    输出共n行,每行一个整数,第i行为第i小的和。数据保证在长整型范围内。

    样例输入

    3
    1 2 5
    2 4 7
    

    样例输出

    3
    4
    5

    先是在学校做了这道题,被归到了“队列”标签里,然后因为是求前n个最小值,那么肯定就是用优先队列啦。

    我们先来看一个叫做k路归并问题的神奇玩意(抄的百度文库)

     好的,看懂了上面我们进行下一步!把A和B数组所有元素的和看作n个有序表(如下)

    如果直接按照k路归并的算法,“把每个表的当前元素放入二叉堆中”需要log n的时间,删除最小值,加入下一个元素(所有表的)又需要log n的时间,总共就需要 n^2 log n 的时间,400000的数据规模铁定爆了!!!

    既然会爆,我们就来优化一下。先思考一下把一个元素放入二叉堆的条件是什么,是它在有序表中的前一个元素被弹出(不是被放入)!所以我们从a1+b1开始扫,每次入堆的时候都打上标记,如果这个元素出堆了,那么就把它所在的有序表的下一个元素入堆!

    综上,O(n log n)!


    代码:

    #include <iostream>
    #include <queue>
    #include <algorithm>
    
    using namespace std;
    int n,a[400005],b[400005],t[400005];
    struct sb
    {
    	int h,bj;
    	friend bool operator< (sb a1,sb b1)//带结构体的优先队列用法
    	{
    		return a1.h>b1.h;
    	}
    };
    
    priority_queue<sb> q;
    
    inline void write(int x)//快速写入
    {
         if(x>9) write(x/10);
         putchar(x%10+'0');
    }
    
    int main()
    {
    	ios::sync_with_stdio(0);
    	
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	for(int i=1;i<=n;i++) cin>>b[i];
    	
    	for(int i=1;i<=n;i++)
    	{
    		sb temp;
    		temp.h=a[i]+b[++t[i]];
    		temp.bj=i;
    		q.push(temp);
    		write(q.top().h);
    		putchar('
    ');
    		int bjt=q.top().bj;
    		if(t[bjt]<n)
    		{
    			temp.h=a[bjt]+b[++t[bjt]];
    			temp.bj=bjt;
    		}
    		q.push(temp);
    		q.pop();
    	}
    } 
    

      

  • 相关阅读:
    Gym
    Gym
    Gym
    Gym
    Gym
    hdu2586 LCA带边权的Targan算法
    bryce1010专题训练——LCA
    POJ1470 LCA (Targan离线)
    bryce1010专题训练——LCT&&树链剖分
    模板——2.7 欧拉函数
  • 原文地址:https://www.cnblogs.com/huaruoji/p/12005435.html
Copyright © 2011-2022 走看看