HDU 4911 (樹狀陣列求逆序數+離散化)
阿新 • • 發佈:2018-12-24
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=4911
題意:最多可以交換K次,就最小逆序對數。
思路:逆序數定理,當逆序對數大於0時,若ai<ai+1,那麼交換後逆序對數+1,反之-1。所以只需要求一下逆序數的個數就行了。逆序數的求解可以用樹狀陣列。我們用樹狀陣列維護某個區間中數字出現的個數,將原資料按其原來順序插入樹狀陣列,第i個數字插入的方式為將樹狀陣列的第a[i]位設為1,同時更新覆蓋到它的父區間,sum(a[i])可求得[1, a[i]]的區間和,這恰好代表第i個數字前小於等於它的個數,等於的只可能是自身,故小於它的有sum(a[i])-1個,那麼大於它的顯然就有i-1-(sum(a[i])-1) = i-sum(a[i])個。
要知道樹狀陣列的長度是資料範圍,由於資料比較大,所以要離散化。注意開long long。
#include <bits/stdc++.h> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define pii pair<int,int> #define ll long long const int maxn = 1e5+5; int n, k; bool cmp(pii a, pii b) { return a.first < b.first; } struct BIT { int n, c[maxn*5]; void init(int n) { this -> n = n; mem(c,0); } void add(int p, int x) { for(int i = p; i <= n; i += i&-i) c[i] += x; } ll sum(int p) { ll ans = 0; for(int i = p; i >= 1; i -= i&-i) ans += c[i]; return ans; } }bit; int main() { while(~scanf("%d%d", &n,&k)) { bit.init(n); int x; ll cnt = 0; vector <pii> v; map <ll,ll> mp; v.clear(); mp.clear(); for(int i = 0; i < n; i++) { scanf("%d",&x); v.push_back({x,i+1}); } sort(v.begin(),v.end(),cmp); int c = 1; mp[v[0].second] = c; for(int i = 1; i <= n; i++) { if(v[i].first == v[i-1].first) mp[v[i].second] = c; else mp[v[i].second] = ++c; } for(int i = 1; i <= n; i++) { bit.add(mp[i],1); cnt += i - bit.sum(mp[i]); } printf("%lld\n",max(cnt-k,0LL)); } }