noi.ac day1t3 Sort

传送门

分析

快排的原理是以任意一个数为标准,然后把所有小于它的数换到它的左边,所有大于它的数换到它的右边。我们就使用快排的思路,分治整个区间。对于每个区间以排好序的这个数列的中间位置的值为标准,然后继续分治这个区间,将这个区间左子区间中大于标准的移到左子区间的最右边,将右子区间中小于标准的移到右子区间的最左边,然后翻转左子区间右侧的一部分一直到右子区间的左侧的一部分这一段区间即可。注意为了防止标准在某些情况下变成一个小于区间最小值或大于区间最大值等奇怪情况,我们将原来的读入的a[i]乘上n之后再加i。这样就不受相同的数的影响了。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
long long n,a[60000],b[60000];
inline long long go(long long le,long long ri,long long wh){
      if(le==ri)return le+(a[le]<=wh);
      long long mid=(le+ri)>>1,s=go(le,mid,wh),t=go(mid+1,ri,wh)-1;
      if(s!=mid+1&&t!=mid){
          printf("%lld %lld\n",s,t);
          reverse(a+s,a+t+1);
      }
      return s+t-mid;
}
inline void work(long long le,long long ri){
      if(le==ri)return;
      long long mid=(le+ri)>>1;
      go(le,ri,b[mid]);
      work(le,mid);
      work(mid+1,ri);
      return;
}
int main(){
      long long i,j,k;
      scanf("%lld",&n);
      for(i=1;i<=n;i++){
          long long x;
          scanf("%lld",&x);
          b[i]=a[i]=x*n+i;
      }
      sort(b+1,b+n+1);
      work(1,n);
      printf("%d %d\n",-1,-1);
      return 0;
}
posted @ 2018-09-29 08:50  水题收割者  阅读(146)  评论(0编辑  收藏  举报