黑盒子--C++

一、题目

黑盒子代表一个原始的数据库。

它可以用来储存整数数组,并且它拥有一个特殊变量i。

在最开始,黑盒子是空的,并且i=0。

现在对黑盒子进行一系列的操作处理,操作包括以下两种:

1、ADD(x):表示将x加入到黑盒子中。
2、GET:使i增加1,输出黑盒子中第i小的数值(即将所有数按升序排序后的第i个数)。

下面给出一个具体例子:

序号 操作        i     盒子内数(升序排列后)             输出的值 
1    ADD(3)      0     3   
2    GET         1     3                                    3 
3    ADD(1)      1     1, 3   
4    GET         2     1, 3                                 3 
5    ADD(-4)     2     -4, 1, 3   
6    ADD(2)      2     -4, 1, 2, 3   
7    ADD(8)      2     -4, 1, 2, 3, 8   
8    ADD(-1000)  2     -1000, -4, 1, 2, 3, 8   
9    GET         3     -1000, -4, 1, 2, 3, 8                1 
10   GET         4     -1000, -4, 1, 2, 3, 8                2 
11   ADD(2)      4     -1000, -4, 1, 2, 2, 3, 8   

为了方便描述,下面我们定义两个序列:

1、A(1),A(2),…,A(M):这个序列由加入到黑盒子内的所有元素按加入顺序排列后得到,上例中的A序列为(3,1,-4,2,8,-1000,2)。

2、u(1),u(2),…,u(N): 这个序列的第i项表示的是第i次GET操作时,盒子内元素的数量。上例中的u序列为(1,2,6,6)。

现在请你根据给出的序列A和u求出操作过程中输出的所有数值。

输入格式

扫描二维码关注公众号,回复: 8916643 查看本文章

输入包括三行。

第一行包含两个整数M和N,表示A序列和u序列的长度。

第二行包含M个整数,表示A序列的每一个元素。

第三行包含N个整数,表示u序列的每一个元素。

同行每个数之间用空格隔开。

输出格式

输出操作过程中所有GET操作输出的数值。

每个数值占一行。

数据范围

|A(i)|<=2∗109|A(i)|<=2∗109,
1≤N≤M≤300001≤N≤M≤30000,
对于所有pp(1≤p≤N1≤p≤N), p≤u(p)≤Mp≤u(p)≤M成立

输入样例:

7 4
3 1 -4 2 8 -1000 2
1 2 6 6

输出样例:

3
3
1
2
难度:中等
时/空限制:1s / 64MB
总通过数:113
总尝试数:193
来源:《算法竞赛进阶指南》

二、思路

这道题考察了大顶堆的概念,通过维护序列数据的小顶堆和大顶堆(小根堆或大根堆),在这个维护的过程中,搜索的顺序要非常注意:

/*
算法思路的步骤:
第一步:从数论的角度去审题,抽出其数据形式,关系,递推公式。
第二步:从数据结构的角度出发,设计出算法题解操作步骤,一般来说数据结构和操作具有耦合性(即算法结构与算法操作具有对应关系)。
第三步:从程序设计出发,实现程序。
*/

/*

算法搜索的顺序:不重不漏的枚举;状态变量的存储

*/

三、实现


/*算法搜索中的三个问题:1.按什么样的顺序搜索2.怎样枚举才能不重不漏所有情况或变量3.变量或状态用数组还是多个变量存储*/
//算法的一般思路:考察对顶推,用两个堆;来维护一个序列。

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>

using  namespace  std;
const int N=30010;
int  n,m; //n表示ADD操作次数,m表示get操作次数
int a[N],b[N];

int  main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int j=0;j<m;j++)cin>>b[j];
    sort(b,b+m);
    priority_queue<int> left;
    priority_queue<int,vector<int>,greater<int>> right;
    /*题解思想:通过维护大顶堆、小顶堆,完成这个模拟操作操作*/
    //b[m]数组暗含了add(x)和get两个操作
    int i=0,j=0;  //枚举操作确定索引变量
    //程序设计
    while(i<n || j<m)  //设计:一步一步操作
    {
      while(j<m && b[j]==i)
        {
           //get操作  在i个元素情况下,get的操作。
           cout<<right.top()<<endl;
           left.push(right.top());
           right.pop();
           j++;
            
        }
        //add操作分两种情况
        int x=a[i];
        if(left.empty()||x>=right.top()) right.push(x);
        else
        {
            left.push(x);
            right.push(left.top());
            left.pop();
        }
        i++;//i表示数组a的索引号
    }
    return 0;
}
发布了21 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_40405758/article/details/99294994
今日推荐