[noi32]sort
先解释一下checker.cpp,它的判定标准是2e7,即答案超过2e7就认为代价过大了。
首先,很容易想到的办法是直接对其快排,从外到内交换区间即可,然而这样会被邪恶的出题人给卡掉(当然其实随便一组大数据都能卡)。
由于一次操作可以翻转而不仅仅是交换,所以要将一个区间分成两块仅仅需要经左右两个区间都分成两块后对中间进行一个翻转即可。
来分析一下这种做法的代价:计将一个长度为l区间分成两块的代价为T(l),那么有递推式T(l)=2T(l/2)+l,即$T(l)=l\ log_{2}l$。然后计将一个长度为l的区间排好序的代价为T’(l),有递推式$T'(l)=2T'(l/2)+T(l)=2T'(l/2)+l\ log_{2}l$,解得$T'(l)=l\ log_{2}^{2}l$,即总代价(或者说总时间复杂度)为$o(l\ log_{2}^{2}l)$,看上去似乎差不多就是2e7,但实际上是可以通过的
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mid (l+r>>1) 4 map<int,int>mat; 5 int n,a[50001],b[50001]; 6 void rev(int l,int r,int k){ 7 if (l==r)return; 8 rev(l,mid,k); 9 rev(mid+1,r,k); 10 int i=mid+1,j=mid; 11 while ((i>l)&&(a[i-1]>k))i--; 12 while ((j<r)&&(a[j+1]<=k))j++; 13 if (i<j)printf("%d %d\n",i,j); 14 reverse(a+i,a+j+1); 15 } 16 void kspx(int l,int r){ 17 if (l==r)return; 18 rev(l,r,mid); 19 kspx(l,mid); 20 kspx(mid+1,r); 21 } 22 int main(){ 23 scanf("%d",&n); 24 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 25 memcpy(b,a,sizeof(b)); 26 sort(b+1,b+n+1); 27 for(int i=1;i<=n;i++)mat[b[i]]=i; 28 for(int i=1;i<=n;i++)a[i]=mat[a[i]]--; 29 kspx(1,n); 30 printf("-1 -1"); 31 }