Minimum Inversion Number
题目链接:https://vjudge.net/problem/HDU-1394
思路
在线段树中维护每个数当前出现的次数,然后一个一个添加,每次添加前看有多少个数是大于自己的,然后加在逆序对总数上面就行。之后再循环一边,因为是把第一个放在最后面去,所以就是先减去小于自己的,然后再加上大于自己的。
代码
#include<bits/stdc++.h> #define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0) #define debug freopen("in.txt","r",stdin),freopen("out.txt","w",stdout); using namespace std; typedef long long ll; typedef pair<int,int> pii; const int maxn = 1e6+10; using namespace std; int N; int arr[5050]; struct node { int l,r; int v; }tr[5050*4]; void pushup(int u){ tr[u].v = tr[u*2].v + tr[u*2+1].v; } void build(int l,int r,int u = 1){ tr[u] = {l,r,0}; if(l == r) return ; int mid = (l+r)>>1; build(l,mid,u*2); build(mid+1,r,u*2+1); pushup(u); } void modify(int idx,int v,int u = 1){ if(tr[u].l == idx && tr[u].r == idx) tr[u].v = 1; else{ int mid = (tr[u].l + tr[u].r) >>1; if(idx<=mid) modify(idx,v,u*2); else modify(idx,v,u*2+1); pushup(u); } } int query(int l,int r,int u = 1){ if(l<= tr[u].l && tr[u].r <= r) return tr[u].v; else{ int mid = (tr[u].l + tr[u].r)>>1; int sum = 0; if(l<=mid) sum += query(l,r,u*2); if(r>mid) sum += query(l,r,u*2+1); return sum; } } int main(){ // debug; ios; while(cin>>N){ memset(tr,0,sizeof tr); build(1,N); for(int i = 1;i<=N;i++) cin>>arr[i],arr[i]+=1; int cnt = 0,res = 1e9; for(int i = 1;i<=N;i++){ cnt += query(arr[i]+1,N); modify(arr[i],1); } for(int i = 1;i<=N;i++){ if(arr[i]-1 >=1) cnt -= query(1,arr[i]-1); if(arr[i]+1 <=N) cnt += query(arr[i]+1,N); res = min(res,cnt); } cout<<res<<endl; } return 0; }