题目:
时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C++ 65536K,其他语言131072K 64bit
IO Format:%lld
题目描述
For this problem, you will write a program that reads in a sequence of
32-bit signed integers. After each odd-indexed value is read, output
the median (middle value) of the elements received so far.
输入描述:
The first line of input contains a single integerP(1≤P≤1000), which is the number of data sets that follow. The
first line of each data set contains the data set number, followed by
a space, followed by an odd decimal integer (1≤M≤9999), giving the total number of signed integers to be
processed. The remaining line(s) in the dataset consists of the
values, 10 per line, separated by a single space. The last line in the
dataset may contain less than 10 values.
输出描述:
For each data set the first line of output contains the data set
number, a single space and the number of medians output (which should
be one-half the number of input values plus one). The output medians
will be on the following lines, 10 per line separated by a single
space. The last line may have less than 10 elements, but at least 1
element. There should be no blank lines in the output.
示例1
输入
3
1 9
1 2 3 4 5 6 7 8 9
2 9
9 8 7 6 5 4 3 2 1
3 23
23 41 13 22 -3 24 -31 -11 -8 -7
3 5 103 211 -311 -45 -67 -73 -81 -99
-33 24 56
输出
1 5
1 2 3 4 5
2 5
9 8 7 6 5
3 12
23 23 22 22 13 3 5 5 3 -3
-7 -3
题意:
给你m个数,一次输入,每当输入的个数为奇数时,输出按大小排列最中间的数
比如1 5 6 7 8
一开始输入1,输出1
然后输入1 5,不输出
输入1 5 6,输出5
输入1 5 6 7,不输出
输入1 5 6 7 8,输出6
题解一:
可以用堆来做
w1为大堆,w1用于存放小值
w2为小堆,w2存放大值
比如上面那个例子1 5 6 7 8
奇数位存在w1,偶数存在w2
如果w1.top()>w2.top(),就是w1的最大比w2的最小值大,就将这两个值互换,始终保证,w1的值比w2的任意一个都小,这样无论数据怎么读入,w1的最大值始终都是最中间的数
看下面模拟:
第一轮:
w1:1
w2:0
二:
w1:1
w2:5
三:
w1:1 6
w2:5
6>5
w1:1 5
w2:6
四
w1:1 5
w2: 7 6
五
w1:1 5 8
w2: 7 6
8>6
w1:1 5 6
w2; 7 8
这样每奇数轮,w1的top位就是答案
#include <iostream>
#include<queue>
#include<cstdio>
using namespace std;
priority_queue<int>w1;//默认为大堆,从大到小
priority_queue<int,vector<int>,greater<int> >w2;//默认为小堆
int main()
{
// freopen("in.txt","r",stdin);
//ios::sync_with_stdio(0);
int n;
cin>>n;
int case1=0;
int p,m,x;
int minn,maxx;
while(n--)
{
cin>>p>>m;
case1=0;
printf("%d %d\n",p,m/2+1);
for(int i=1;i<=m;i++)
{
cin>>x;
if(i%2==1)w1.push(x);
else w2.push(x);
if(i!=1)
{
minn=w1.top();
maxx=w2.top();
if(minn>maxx)
{
w1.pop();
w2.pop();
w1.push(maxx);
w2.push(minn);
}
}
if(case1!=0&&case1%10==0)
{
cout<<endl;
case1=0;
}
if(i%2==1)
{
if(i==m)cout<<w1.top();
else
printf("%d ",w1.top());
case1++;
}
}
cout<<endl;
while(!w1.empty())w1.pop();
while(!w2.empty())w2.pop();
}
return 0;
}
(这个题的格式我一开始一直没注意。。。)
题解二:
我看很多人都是这么做的,但是只能过50%的数据。。包括我自己
我看了清楚姐姐的代码稍微改一下:
我们在读入一个数后,直接与w1.top比较,小于就存进去,大了就存w2里
当w1的数量多了,就把堆顶拿出给w2(小根堆)
w2多了就给大根堆
这样维护出来其实和上面的方法差不多
因为总数是奇数,两个堆数量一定不一样,多的那方,堆顶就是答案
代码:
清楚阿姨(狗头 )代码:
#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>, greater<int> > q2; //小根堆 ,存较大的一半的数
priority_queue<int> q1; //大根堆 ,存较小的一半的数
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
while(!q1.empty()) q1.pop();
while(!q2.empty()) q2.pop(); //优先队列没有clear函数,要一个一个弹出
int m, n;
scanf("%d %d", &m ,&n);
printf("%d %d\n", m, (n+1)/ 2);
int x;
scanf("%d", &x);
q1.push(x);
printf("%d ", x);
for(int i = 2; i <= n; i++)
{
int x;
scanf("%d", &x);
if (x <= q1.top()) q1.push(x); //如果当前值比大根堆堆顶小,说明在小的这二分之一,塞进大根堆
else q2.push(x);
int num1= q1.size();
int num2= q2.size();
if (num1 - num2 > 1) //大根堆里面元素多了,把堆顶拿出来塞近小根堆
{
q2.push(q1.top());
q1.pop();
}
else if(num2 - num1 >1) //小根堆里面元素多了,把堆顶拿出来塞近大根堆
{
q1.push(q2.top());
q2.pop();
}
if (i % 2 == 1) //目前的元素个数是奇数
{
num1 = q1.size();
num2 = q2.size();
if(num1 > num2) printf("%d ", q1.top()); //中位数在大根堆
else printf("%d ", q2.top()); //中位数在小根堆
if (i % 20 == 19 && i!=n) printf("\n");
}
}
printf("\n");
}
return 0;
}