Jzoj3542 冒泡排序

来源:互联网 发布:奔驰诊断软件下载 编辑:程序博客网 时间:2024/06/17 13:11
下面是一段实现冒泡排序算法的C++代码:

for (int i=1;i<=n;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中元素的值会是什么样的呢?

是一个模拟题也~

我们先来考虑一个数的移动情况

假设x前面有t[x]个数比x要大,那么显然在i<=t[x]的时候,x每次都会被前移一位,之后就不会再向前了

又因为,前移的次数=swap的次数,所以我们可以先求出t数组,让后二分i,使得swap的次数不超过k

设枚举出来的这个i的上界为m,那么所有t[x]>=m的数必然前移了m位,让后我们将所有t[x]<m的x拿出来排序,然后插入回原来的空格中(显然这部分的数是排序好了的,因为这些数不会再前移,所以必然有序)

最后由于没到k次,差的部分直接用模拟补上

#pragma GCC opitmize("O3")#pragma G++ opitmize("O3")#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int n,v[1000010],t[1000010],b[1000010]; long long k;struct fenwick{long long w[1000010],s;inline void clear(){ memset(w,0,sizeof w); }inline void add(int x,int v=1){ for(;x<=n;x+=x&-x) w[x]+=v; }inline long long sum(int x){ for(s=0;x;x&=x-1) s+=w[x]; return s; }} r,c;int main(){scanf("%d%lld",&n,&k);for(int i=1;i<=n;++i){scanf("%d",v+i);t[i]=i-r.sum(v[i])-1; r.add(v[i]);}r.clear();for(int i=1;i<=n;++i) r.add(t[i]+1),c.add(t[i]+1,t[i]);int l=0,R=n;for(int m;l<R;){m=l+R+1>>1;if(k>=c.sum(m+1)+m*(n-r.sum(m+1))) l=m;else R=m-1;}k-=c.sum(l+1)+l*(n-r.sum(l+1));for(int i=1;i<=n;v[i++]=0)if(t[i]>=l)v[i-l]=v[i]; else b[++*b]=v[i];sort(b+1,b+1+*b);for(int i=n;i;--i) if(!v[i]) v[i]=b[(*b)--];for(int j=1;j<n && k;++j)if(v[j]>v[j+1]) swap(v[j],v[j+1]),--k;if(k) puts("Impossible!"); else for(int j=1;j<=n;++j) printf("%d ",v[j]);}