正题
大意
一个序列,每次将一个单调下降的区间翻转,求最少次数将这个序列变成单调上升。
解题思路
考虑将O(n2)O(n2)的暴力转换。
我们先将开始时单调下降的区间翻转,然后我们会发现只有每个区间的边界才会需要交换,因为每个区间已经是单调上升的了。但是每次交换又可能会出现新的需要交换的,这就很像冒泡排序。而冒泡排序需要交换的次数就是逆序对的个数。
代码
#include<cstdio>
#include<algorithm>
long long h[100001],b[100001],n,s,ls,w;
void swap(long long &x,long long &y)
{long long z=x;x=y;y=z;
}
void mage(long long low,long long mid,long long hig)//归并排序求逆序对
{long long p1=low,g=low;long long p2=mid+1;while (g<=hig){if (p1>mid) {b[g]=h[p2]; p2++;}else if (p2>hig) {b[g]=h[p1]; p1++;}else if (h[p1]>h[p2]) {b[g]=h[p1]; p1++; s+=hig-p2+1;}else {b[g]=h[p2]; p2++;}g++;}for (long long i=low;i<=hig;i++) h[i]=b[i];
}
void magesort(long long low,long long hig)
{if (low<hig){long long mid=(low+hig)/2;magesort(low,mid);magesort(mid+1,hig);mage(low,mid,hig);}
}
int main()
{scanf("%d",&n);for (long long i=1;i<=n;i++){scanf("%d",&h[i]);}ls=1;h[n+1]=2147483647;for (long long i=1;i<=n;i++)//第一次交换{if (h[i+1]>h[i]){w=(ls+i)/2;for (long long j=ls;j<=w;j++)swap(h[j],h[i-j+ls]);if (i-ls!=0) s++;ls=i+1;}}magesort(1,n);printf("%d",s);
}
休息!休息一下!