利用线段树在nlogn的时间复杂度内求一段数的逆序。
由于给的序列是由0 ~ n -1组成的,求出初始的逆序之后可以递推出移动之后的逆序数。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int maxn = 5555; int tree[maxn << 2]; int n; void BuildTree(int L,int R,int pos){ //建树 tree[pos] = 0; if(L == R) return ; int m = (L + R) >> 1; BuildTree(L,m,pos << 1); BuildTree(m + 1,R,(pos << 1)|1); return ; } void UpDate(int aim,int L,int R,int pos){ if(L == R){ tree[pos] ++; return ; } int m = (L + R) >> 1; if(aim <= m) UpDate(aim,L,m,pos << 1); else UpDate(aim,m + 1,R,(pos << 1)|1); tree[pos] = tree[pos << 1] + tree[(pos << 1)|1]; return ; } int Query(int l,int r,int L,int R,int pos){ if(l <= L && R <= r) return tree[pos]; int m = (L + R) >> 1; int ans = 0; if(l <= m) ans += Query(l,r,L,m,pos << 1); if(m < r) ans += Query(l,r,m + 1,R,(pos << 1)|1); return ans; } int main(){ while(scanf("%d",&n) != EOF){ BuildTree(0,n - 1,1); int Sum = 0; int x[maxn]; for(int i = 0 ; i < n ; i++){ //利用nlog(n)时间复杂度求逆序数 scanf("%d",&x[i]); Sum += Query(x[i], n - 1,0,n - 1,1); UpDate(x[i],0,n - 1,1); } int ans = Sum; for(int i = 0 ; i < n; i++){ Sum = Sum + n - 2 * x[i] - 1; ans = min(ans,Sum); } printf("%d\n",ans); } return 0; }
时间: 2024-10-10 09:38:41