『8.20 模拟赛』冒泡排序

题目描述

给定n,k,和一个长度为n的序列,请输出这个序列冒泡排序k次之后的结果。

解题思路

我们观察上面给出的伪代码,可以发现这是一段把代码排序成升序的代码,那我们来考虑一下冒牌排序的几个特征。

一个大的数要向右交换,但是一次交换之后就可以换很多位置,所以换一次就不知道跑到哪里去了,所以很难维护。

一个小的数每次最多和它左边的更大的数交换一次,所以一次最多向左边跑一个位置,比大数不知道好维护到那里去了。

进一步思考,k次交换之后,最多可以向左跑k步,也就是说k+1位置的数最远能跑到1的位置上来,那我们就可以大胆的猜想了,前k+1个数在第一轮交换之后最小的数会到第一个位置。假如前k+1个中最小的数没能跑到第一个位置,那说明一定有一个比它小的数会在它的左边挡它,和我们的假设矛盾,所以猜想成立。

以此类推,第k+2个数最多到第二个位置上,按照我们的结论,第二个位置上的数应该是1 ~ k+2之间除去第一个位置的数以外的最小的数。

接着推下去,我们就完成了所有的数的位置的计算。

可以看出来,我们需要维护一个最小值,显然可以使用线段树,也可以使用优先队列,注意push的时候要用负值。

代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<queue>
 6 using namespace std;
 7 const int maxn=100050;
 8 int n,k;
 9 int a[maxn];
10 priority_queue<int>q;
11 int main(){
12     scanf("%d%d",&n,&k);
13     for(register int i=1;i<=n;i++)scanf("%d",&a[i]);
14     for(register int i=1;i<=min(n,k+1);i++){
15         q.push(-a[i]);
16     }
17     for(register int i=2;i+k<=n;i++){
18         printf("%d\n",-q.top());
19         q.pop();
20         q.push(-a[i+k]);
21     }
22     while(!q.empty()){
23         printf("%d\n",-q.top());
24         q.pop();
25     }
26 }

猜你喜欢

转载自www.cnblogs.com/Fang-Hao/p/9507869.html
今日推荐