Official

E - 隣接スワップで転倒数を減らせ / Reduce Inversions with Adjacent Swaps Editorial by physics0523


この問題は、 転倒数 を求めるのとそう変わらない手順で求めることができます。

\(P\) の転倒数を \(inv\) として、答えは \(\max(0,inv-K)\) です。なぜなら、一度の隣接 swap で転倒数を \(1\) 減らすことができ、また、 \(2\) 以上減らすことはできないからです。

少し丁寧に証明してみましょう。
転倒数は \(i<j\) かつ \(P_i > P_j\) を満たす \((i,j)\) の組の個数ですが、数列が昇順ソートされていない限り必ず \(P_i > P_{i+1}\) なる \(i\) を見つけることができます。ここを入れ替えることで転倒数を \(1\) 減らすことができます。
また、隣接 swap で前後関係が変わる要素の組は、隣接 swap で触った \(2\) つの要素の組以外に存在しないので、転倒数を \(2\) 以上減らすことはできません。

転倒数は Fenwick Tree を用いることで求められます。

実装例 (C++):

#include<bits/stdc++.h>
#include<atcoder/fenwicktree>

using namespace std;
using namespace atcoder;
using ll=long long;

int main(){
  ll N,K;
  cin >> N >> K;
  fenwick_tree<ll> fw(N+5);
  ll res=0;
  for(ll i=0;i<N;i++){
    ll P;
    cin >> P;
    res+=(i-fw.sum(0,P));
    fw.add(P,1);
  }
  cout << max(0ll,res-K) << "\n";
  return 0;
}

posted:
last update: