点击打开链接
题意:输入n个数的序列,依次将第一个数放到最后面,求这期间的最小逆序数
思路:挺简单的一道线段树,下面注释中有解释。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn=5010; const int inf=0x3f3f3f3f; int num[maxn*4]; void buildtree(int le,int ri,int node){ num[node]=0; if(le==ri) return ; int t=(le+ri)>>1; buildtree(le,t,node<<1); buildtree(t+1,ri,node<<1|1); } void update(int pos,int le,int ri,int node){ if(le==ri){ num[node]++; return ; } int t=(le+ri)>>1; if(pos<=t) update(pos,le,t,node<<1); else update(pos,t+1,ri,node<<1|1); num[node]=num[node<<1]+num[node<<1|1]; } int query(int l,int r,int le,int ri,int node){ if(l<=le&&ri<=r) return num[node]; int t=(le+ri)>>1; int ans=0; if(l<=t) ans+=query(l,r,le,t,node<<1); if(r>t) ans+=query(l,r,t+1,ri,node<<1|1); return ans; } int A[maxn]; int main(){ int n; while(scanf("%d",&n)!=-1){ int sum=0; buildtree(1,n,1);//因为是空树,也可以直接memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ scanf("%d",&A[i]); sum+=query(A[i]+1,n,1,n,1); // query(A[i]+1,n,1,n,1)代表的是A[i]+1->n的区间和,如果这之间和为0, // 代表还没有大于A[i]+1的数出现过,所以逆序数为0; // query后的结果如果为k,则说明已经有k个比A[i]+1大的数已经输了 update(A[i]+1,1,n,1); } int ans=sum; for(int i=0;i<n;i++){ sum+=(n-A[i]*2-1); ans=min(ans,sum); } printf("%d\n",ans); } return 0; }