$\newcommand{\O}{\mathrm{O}}$
転倒数と呼ばれる数を計算するアルゴリズム. 数列 $\{ a_i \}$ の転倒数とは 「$a_i > a_j\ (i < j)$ となる組 $(i, j)$ の数」 のことでバブルソートの交換回数とも一致する.
この値は BIT を用いて効率よく計算できる(アルゴリズムは蟻本などを参照してください).
時間計算量: $\O (n \log n)$
template<typename T> class BIT { private: int n; vector<T> bit; public: // 0_indexed で i 番目の要素に x を加える void add(int i, T x){ i++; while(i < n){ bit[i] += x, i += i & -i; } } // 0_indexed で [0,i] の要素の和(両閉区間!!) T sum(int i){ i++; T s = 0; while(i > 0){ s += bit[i], i -= i & -i; } return s; } BIT(){} //初期値がすべて0の場合 BIT(int sz) : n(sz+1), bit(n, 0){} BIT(const vector<T>& v) : n((int)v.size()+1), bit(n, 0){ for(int i = 0; i < n-1; i++){ add(i,v[i]); } } void print(){ for(int i = 0; i < n-1; i++){ cout << sum(i) - sum(i-1) << " "; } cout << "\n"; } //-1スタート void print_sum(){ for(int i = 0; i < n; i++){ cout << sum(i-1) << " "; } cout << "\n"; } }; // u を昇順にソートするのに必要な交換回数(転倒数) (u は {0,..., n-1} からなる重複を許した長さ n の数列) long long inv_count(const vector<int>& u) { int n = (int)u.size(); BIT<int> bt(n); long long ans = 0; for(int i = 0; i < n; i++){ ans += i - bt.sum(u[i]); bt.add(u[i], 1); } return ans; } // u を v に変換するのに必要な交換回数(転倒数) // (u, v は {0,..., n-1} からなる重複を許した長さ n の数列. ただし u, v 全体で各数字の個数は一致するものとする) long long inv_count(const vector<int>& u, const vector<int>& v) { int n = (int)u.size(); vector<vector<int> > p(n); BIT<int> bt(n); for(int i = n-1; i >= 0; --i){ p[u[i]].push_back(i); } long long ans = 0; for(int i = 0; i < n; ++i){ int pos = p[v[i]].back(); p[v[i]].pop_back(); ans += pos - bt.sum(pos); bt.add(pos, 1); } return ans; }
Atcoder : Papple Sort 提出コード