Jzoj3542 冒泡排序
下面是一段实现冒泡排序算法的C++代码:
其中待排序的a数组是一个1~n的排列,swap函数将交换数组中对应位置的值。
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]);
}