Jzoj3542 冒泡排序

下面是一段实现冒泡排序算法的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]);
}

原文地址:https://www.cnblogs.com/Extended-Ash/p/9477178.html