题面

下面是一段实现冒泡排序算法的C++代码:

for (int i=1;i<=n-1;i++) 
for (int j=1;j<=n-i ;j++) 
if(a[j]>a[j+1]) 
swap(a[j],a[j+1]);

其中待排序的a数组是一个1~n的排列,swap函数将交换数组中对应位置的值。

对于给定的数组a以及给定的非负整数k,使用这段代码执行了正好k次swap操作之后数组a中元素的值会是什么样的呢?

n<=1e6  k<=1e12

题解

这题要开long long

这是道结论题,

在尝试了各种方法之后,我们尝试直接构造答案数组。 

考虑每个数在答案数组里的位置。 

定义j扫一遍为一轮。 

分析发现:

1:每个数,每轮最多向左移动一个位置。

继续:

2:若一个数左边有比它大的数,它就一定会左移一个位置。 

2逆:若它左移一个位置,则它的左边一定有数比它大。

再继续:

3:设前面有t个数比它大,那么前t轮,每一轮它都会向左移一个位置,然后它就再不左移。

思路似乎已经清晰。 

设经过x轮移动,在过不到一轮就交换k次。 

先来考虑经过刚好x轮移动的情况。

如果t<=x,那么它的位置在哪里? 

这种情况就是,一个数左移到一半就停止不移动了。 

显然它的位置是可求的。 

如果t>x,那么它的位置又在哪里? 

这种数不会再左移,也就说明它的左边没有比它大的数。 

推出结论:

4:这部分数的位置一定是随着值而递增的。

我们现在已经知道一部分数的具体位置了,把剩下的数按从小到大的顺序填到空位置里就好了。

现在已经知道了x轮移动的答案,还剩下一点交换次数,就直接来一轮冒泡排序就好了。

5:发现:交换次数=左移次数。

根据结论2的逆结论,统计每一轮的左移次数就好了。

- by  我们都是星尘

那么,如果我们知道k次交换后一共完整地进行了x轮的话,就可以把“

for(int i=1; i<n; i++)

” 这重循环给省掉,而直接O(n)计算残缺的第二重循环,既然已经知道x轮移动的答案,而这个答案肯定是单调递增的,就可以通过二分枚举x。

CODE(加freopen)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<algorithm>
#define LL long long
#define MAXN 1000005
#define lowbit(x) (((-x) & (x)))
using namespace std;
inline LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
return x * f;
}
LL n,m,i,j,s,o,k,cnt;
LL a[MAXN],b[MAXN];
LL c[MAXN];
LL f[MAXN];
priority_queue<int> q;
void addtree(int x,LL y) {
for(int i = x;i <= n;i += lowbit(i)) c[i] += y;return ;
}
inline LL sum(int x) {
LL ans = 0;
for(int i = x;i > 0;i -= lowbit(i)) ans += c[i];
return ans;
}
inline LL check(LL a) {
LL ans = 0;
for(int i = 1;i <= n;i ++) {
ans += min(a,f[i]);
}
return ans;
}
LL solve(LL l,LL r) {
// printf("%d %d\n",l,r);
if(l >= r - 1) {
if(check(r) <= m) return r;
return l;
}
LL mid = (l + r) / 2;
if(check(mid) <= m) return solve(mid,r);
return solve(l,mid);
}
int main() {
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
n = read();m = read();
for(int i = 1;i <= n;i ++) {
a[i] = read();
addtree(a[i],1);
f[i] = sum(n) - sum(a[i]);
}
// for(int i = 1;i <= n;i ++) printf("s:%d ",sum(i));putchar('\n');
LL aa = solve(0,n);
m -= check(aa);
for(int i = 1;i <= n;i ++) {
if(f[i] >= aa) {
b[i - aa] = a[i];
}
else {
q.push(a[i]);
}
}
for(int i = n;i > 0;i --) {
if(!b[i]) {
b[i] = q.top();q.pop();
}
}
// for(int i = 1;i <= n;i ++) {
// printf("%d ",b[i]);
// }putchar('\n');
// printf("%d\n",m);
for(int i = 1;i < n;i ++) {
if(!m) break;
if(b[i] > b[i + 1]) {
swap(b[i],b[i + 1]);
m --;
}
}
if(m > 0) {
printf("Impossible!\n");
}
else {
for(int i = 1;i <= n;i ++) {
printf("%d ",b[i]);
}putchar('\n');
}
return 0;
}

JZOJ3542冒泡排序的更多相关文章

  1. [C#][算法] 用菜鸟的思维学习算法 -- 马桶排序、冒泡排序和快速排序

    用菜鸟的思维学习算法 -- 马桶排序.冒泡排序和快速排序 [博主]反骨仔 [来源]http://www.cnblogs.com/liqingwen/p/4994261.html  目录 马桶排序(令人 ...

  2. 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)

    本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...

  3. Html5 冒泡排序演示

    冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法. 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要 ...

  4. javascript冒泡排序

    数组冒泡排序算法(升序) 升序:小数在前,大数在后 冒泡排序的原则:每次比较相邻两个元素,如果前一个数>后一个数,说明违反升序的要求,就将两数交换位置.否则,保持不变.继续比较下一对. 例如:玩 ...

  5. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

  6. C#冒泡排序算法

    用了两种形式的数据,一个是泛型List,一个是数据int[].记录一下,作为自己学习过程中的笔记. using System; using System.Collections.Generic; us ...

  7. python排序之二冒泡排序法

    python排序之二冒泡排序法 如果你理解之前的插入排序法那冒泡排序法就很容易理解,冒泡排序是两个两个以向后位移的方式比较大小在互换的过程好了不多了先上代码吧如下: 首先还是一个无序列表lis,老规矩 ...

  8. 以冒泡排序为例--malloc/free 重定向stdin stdout

    esort.c 代码如下,可关注下mallloc/free,freopen重定向的用法,排序为每轮将最小的数放在最前面: #include<stdio.h> #include<mal ...

  9. 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析之后续补充说明(有图有真相)

    如果你觉得我的有些话有点唐突,你不理解可以想看看前一篇<C++之冒泡排序.希尔排序.快速排序.插入排序.堆排序.基数排序性能对比分析>. 这几天闲着没事就写了一篇<C++之冒泡排序. ...

随机推荐

  1. NET架构师的基本职责

    NET架构师的基本职责1 职责 对本公司大健康平台提出技术研究及可行性报告; 结合需求设计高扩展性.高性能.安全.稳定.可靠的技术系统; 可以通过配置实现业务需求的变化,跟踪并研究***并应用于产品; ...

  2. 基于slate构建文档编辑器

    基于slate构建文档编辑器 slate.js是一个完全可定制的框架,用于构建富文本编辑器,在这里我们使用slate.js构建专注于文档编辑的富文本编辑器. 描述 Github | Editor DE ...

  3. 在mybatis中使用sum函数返回对象为Null

    首先大家看一下我的XML中的SQL .DAO  和实体对象 XML DAO PO 乍一看 没毛病. 但是在Mybatis中使用sum函数,如果返回值是0(就是你在Navicat中运行的的sql正常,结 ...

  4. Mysql错误:The server time zone value is unrecognized or represents more than one time zone

    方法1.修改Mysql的时区为东8区,执行如下命令即可: PS:这种方式每次开机都要配置的 set global time_zone='+8:00' 方法2.配置改成这样的 spring.dataso ...

  5. NC16746 神奇盘子

    NC16746 神奇盘子 题目 题目描述 有一个神奇的盘子,形状为圆形.盘子上面爬着一个大象(视作一个点).由于现实的扭曲,当大象在盘子某个直径的一端的时候,可以瞬间传送至直径的另一端.现在大象想去盘 ...

  6. ArrayList集合存储基本数据类型

    如何存储基本数据类型 ArrayList对象不能存储基本类型,只能存储引用类型的数据.类似 <int> 不能写,但是存储基本数据类型对应的 包装类型是可以的.所以,想要存储基本类型数据, ...

  7. 攻防世界进阶区MISC ——56-60

    56.low 得到一张bmp,世纪之吻,扔进kali中,binwalk,zsteg,无果,再放进stegsolve中,虽然发现小的数据块,但是过滤通道得不到任何信息,猜测是要用脚本进行 # lsb隐写 ...

  8. ApiDay002_02 Object中的包装类

    1.Object:对象/东西 是所有类的鼻祖,所有类都直接或间接继承了Object, 万物皆对象,为了多态 Objec中有几个经常被派生类重写的方法:toString()和equals(); 调用to ...

  9. 浅谈spring-createBean

    目录 找到BeanClass并且加载类 实例化前 实例化 Supplier创建对象 工厂方法创建对象 方法一 方法二 推断构造方法 BeanDefionition 的后置处理 实例化后 属性填充 sp ...

  10. Seata-初体验以及避坑

    Seata是什么 这里引用官方解释 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用 ...