题意:
现在告诉你有n个数,然后你每次可以交换相邻两个序列中的数字,然后问你最少几次可以把这个序列变成一个递增的有序序列。
思路:
今天重新学习了一下归并排序,这个排序是增量的思想,但是又有点分治+递归。
至于怎样用归并来求逆序数的对数呢?我们把序列分成两半,然后如果后面那半的数小于前面那半的数的话,那么就说明在前面那个[p,mid)区间中有mid-p这么多的逆序数,因为归并排序保证了已经划分好的序列是有序的,余下的也是依次类推就好。
并且最好全部改成I64d的形式,要不然会WA。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 500050
typedef __int64 ll;
ll a[maxn],t[maxn],cnt=0;
void merge_sort(ll x,ll y){
if(y-x>1){
ll mid=x+(y-x)/2;
ll p=x,q=mid,i=x;
merge_sort(x,mid);
merge_sort(mid,y);
while(p<mid||q<y){
if(q>=y||(p<mid&&a[p]<=a[q])) t[i++]=a[p++];
else t[i++]=a[q++],cnt+=mid-p;
}
for(ll j=x;j<y;j++) a[j]=t[j];
}
}
int main(){
ll n;
while(~scanf("%I64d",&n)){
if(n==0) break;
memset(a,0,sizeof(a));
memset(t,0,sizeof(t));
cnt=0;
for(int i=0;i<n;i++) scanf("%I64d",&a[i]);
merge_sort(0,n);
printf("%I64d\n",cnt);
}
}