题目大意:
给你一个序列,长度不超过32000,要求用不超过4e6的代价将其排序。
你可以进行的操作形如选定一个区间然后翻转,代价是区间长度。
题解:
考虑快排,现在选定了一个数字(实际应该选择离散化后的中位数),要将小于等于他的放左边,大于放右边。这个怎么搞,你将小于等于的看做0,大于看做1,相当于是把一个01序列排序,这个可以搞一个类似于归并的分治。总复杂度两个log,实现优秀可以通过。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
const int N=33000;
int a[N],b[N];vector<pii> lst;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int rev(int s,int t)
{
lst.pb(mp(s,t));
for(int i=s,j=t;i<=j;i++,j--) swap(a[i],a[j]);
return 0;
}
int mysort(int l,int r,int x)
{
if(l>=r) return 0;
int mid=(l+r)>>1;
mysort(l,mid,x);
mysort(mid+1,r,x);
int p=l,q=mid;
while(p<=mid&&a[p]<=x) p++;
while(q<r&&a[q+1]<=x) q++;
if(p<=mid&&mid<q) rev(p,q);
return 0;
}
int solve(int l,int r)
{
if(l>=r) return 0;int cnt=0;
rep(i,l,r) b[++cnt]=a[i];
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
if(cnt==1) return 0;
int x=b[cnt/2];
mysort(l,r,x);int p=l;
rep(i,l,r) if(a[i]<=x) p=i;
solve(l,p),solve(p+1,r);
return 0;
}
int main()
{
int n=inn();
rep(i,1,n) a[i]=inn();
solve(1,n);
printf("%d\n",int(lst.size()));
Rep(i,lst) printf("%d %d\n",lst[i].fir,lst[i].sec);
return 0;
}