ROI 2018 C

Day2 C Quick Sort

题目大意: 定义对序列 \(\{a_i\}\) 上一段区间 \([l,r]\) 的操作为 提出区间,奇偶分别合并放到两边
给出排列 \(\{a_i\}\) ,求将 \(\{a_i\}\) 排序的方案,要求操作数 \(\le 15000\)
长度 \(n \le 3000\)

题解:
一个显然的想法是从小到大处理每个 \(i\) ,设 \(p\)\(i\) 当前的位置,则操作 \([i,p]\)\((i,p]\) ,能够得到 \(80\) pts。
发现此过程每一步都需要几乎卡满 \(\log\) ,原因是操作后 \(i\) 只会变到 \(\frac{i+p}{2}\) 的位置。
考虑该过程倒过来,此时操作的结果是 中间的被分到两侧 ,这样就降低了局限性。
从大往小做,每次 \(p \rightarrow 2p\) ,分析可知期望操作数是 \(O(n)\) 的。

为了放置被卡,需要一开始随机打乱,即随机若干个区间操作。

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int N=3010;
int n,a[N],t[N],b[N];
vector<pair<int,int>> ans,q;
void push(int l,int r){
	ans.push_back(make_pair(l,r));
	fo(i,l,r)b[i]=a[i];
	int mid=l+r-1>>1;
	fo(i,l,mid)a[l+(i-l)*2+1]=b[i];
	fo(i,mid+1,r)a[l+(i-mid)*2-2]=b[i];
	fo(i,l,r)t[a[i]]=i;
}
void solve(int x){
	int cnt=0;
	for(int p=t[x];p<x;p=t[x]){
		if((p<<1)<=x)push(1,p<<1);
		else push(p*2-x+1,x);
		++cnt;
		// if(cnt==100)
		// 	puts("DEBUG");
	}
}
void output(){
	printf("%d\n",ans.size());
	reverse(ans.begin(),ans.end());
	for(auto it:ans)printf("%d %d\n",it.first,it.second);
}
int main(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	// printf("%d\n",3000);
	// fd(i,3000,1)printf("%d ",i);
	// printf("\n");
	// return 0;
	srand(time(NULL));
	scanf("%d",&n);
	fo(i,1,n){
		int x;
		scanf("%d",&x);
		a[x]=i;t[i]=x;
	}
	fo(i,1,100){
		int l=rand()%n+1,r=rand()%n+1;
		if(l>r)swap(l,r);
		push(l,r);
	}
	fd(i,n,1)
		solve(i);
	output();

	return 0;
}
posted @ 2022-11-15 15:30  Kelvin2005  阅读(44)  评论(0编辑  收藏  举报