题意:给出N个整数(0~n-1),问经过循环移位得到的n个序列中最小的逆序对数。
分析:归并排序,线段树,树状数组均可解之。
Source Code(线段树):
#include<cstdio> #include<algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 const int maxn=5005; int sum[maxn<<2],num[maxn]; void PushUp(int rt){ sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void build(int l,int r,int rt){ sum[rt]=0; if(l==r) return ; int m=(l+r)>>1; build(lson); build(rson); PushUp(rt); } void update(int p,int l,int r,int rt){ if(l==r){ sum[rt]++; return ; } int m=(l+r)>>1; if(p<=m) update(p,lson); else update(p,rson); PushUp(rt); } int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R) return sum[rt]; int m=(l+r)>>1; int ret=0; if(L<=m) ret+=query(L,R,lson); if(R>m) ret+=query(L,R,rson); return ret; } int main() { int n,cnt; while(~scanf("%d",&n)){ build(0,n-1,1); cnt=0; for(int i=0;i<n;i++){ scanf("%d",&num[i]); cnt+=query(num[i],n-1,0,n-1,1); update(num[i],0,n-1,1); } int ans=cnt; for(int i=0;i<n;i++){ cnt+=(n-num[i]-1)-num[i]; ans=ans<cnt?ans:cnt; } printf("%d\n",ans); } return 0; }
Source Code(归并排序):
#include<cstdio> #include<iostream> using namespace std; const int maxn=5005; int num1[maxn],num2[maxn],temp[maxn]; int sum; void Merge(int l,int mid,int r){ int p=0; int i=l,j=mid+1; while(i<=mid&&j<=r){ if(num1[i]>num1[j]){ sum+=mid-i+1; temp[p++]=num1[j++]; } else temp[p++]=num1[i++]; } while(i<=mid)temp[p++]=num1[i++]; while(j<=r)temp[p++]=num1[j++]; for(i=0;i<p;i++) num1[l+i]=temp[i]; } void MergeSort(int l,int r){ if(l<r){ int mid=(l+r)>>1; MergeSort(l,mid); MergeSort(mid+1,r); Merge(l,mid,r); } } int main() { int n; while(~scanf("%d",&n)){ for(int i=0;i<n;i++){ scanf("%d",&num1[i]); num2[i]=num1[i]; } sum=0; MergeSort(0,n-1); int ans=sum; for(int i=0;i<n-1;i++){ sum+=n-num2[i]-num2[i]-1; ans=ans<sum?ans:sum; } printf("%d\n",ans); } return 0; }