公式

E - 整列の手間 / The Effort of Sorting 解説 by admin

claude4.8opus-high

Summary

This problem asks us to find the minimum number of inversions after performing exactly \(K\) adjacent element swaps on a permutation. By using the property that an adjacent swap changes the number of inversions by \(\pm 1\), we can calculate the answer using only the initial number of inversions, \(T\).

Analysis

Key Observation: Adjacent swaps change the number of inversions by exactly 1

When we swap two adjacent elements \(P_i\) and \(P_{i+1}\), their relative order with all other elements remains completely unchanged. Only the relationship between these two elements is affected.

  • If \(P_i > P_{i+1}\) (descending order), swapping them resolves one inversion, changing the number of inversions by \(-1\).
  • If \(P_i < P_{i+1}\) (ascending order), swapping them creates one inversion, changing the number of inversions by \(+1\).

In other words, each operation increases or decreases the number of inversions by exactly \(1\). The key point is that the parity of the number of inversions flips with each operation.

Case Analysis by the Number of Operations \(K\)

Let \(T\) be the initial number of inversions.

Case 1: \(K \le T\)

We can decrease the number of inversions by \(1\) in each step by choosing and swapping an inverted pair. Since we can use all \(K\) operations to “decrease” the inversions, the minimum achievable value is $\(T - K\)$ .

Case 2: \(K > T\)

First, we can reduce the number of inversions to \(0\) (fully sorted in ascending order) using \(T\) operations. However, since we must perform exactly \(K\) operations, we have to consume the remaining \(K - T\) operations.

From the state where the number of inversions is \(0\), any adjacent swap will inevitably increase the number of inversions by \(+1\). Thus, if we repeatedly “swap and then swap back” any two adjacent elements, the number of inversions will oscillate like \(0 \to 1 \to 0 \to 1 \to \cdots\).

Therefore, the number of inversions after the remaining \(K - T\) operations is determined by its parity: - If \(K - T\) is even, the minimum value is \(0\). - If \(K - T\) is odd, the minimum value is \(1\).

This can be summarized as \((K - T) \bmod 2\).

Issues with a Naive Approach

A naive simulation approach will not run in time because \(K\) can be as large as \(10^{18}\). Based on the analysis above, once we find the initial number of inversions \(T\), we can determine the answer in \(O(1)\) time.

Algorithm

All we need to do is calculate the initial number of inversions \(T\). The number of inversions can be efficiently counted using a BIT (Binary Indexed Tree / Fenwick Tree).

Specific procedure (scanning the array from right to left): 1. Maintain the BIT as the “set of values visited so far”. 2. For the value \(v = P_i\) at position \(i\), find the number of elements smaller than \(v\) that have already appeared to its right using query(v-1), and add this count to \(T\). This corresponds to the number of pairs \((i, j)\) such that \(i < j\) and \(P_i > P_j\) for a fixed \(i\). 3. Register the value \(v\) into the BIT using update(v).

Once the scan is complete, \(T\) will be the total number of inversions. Then, we can output the answer based on the case analysis described above.

Complexity

  • Time Complexity: \(O(N \log N)\) (dominated by the inversion counting using the BIT. The case analysis takes \(O(1)\).)
  • Space Complexity: \(O(N)\) (for the BIT array)

Implementation Points

  • Since \(K\) can be as large as \(10^{18}\), you need to be mindful of using 64-bit integers depending on the programming language (not an issue in Python, which supports arbitrary-precision integers).

  • Since the values form a permutation from \(1\) to \(N\), you can use the values themselves directly as indices in the BIT.

  • The core of this problem lies in the fact that the case analysis boils down to a very simple formula: “\(T - K\) if \(K \le T\), otherwise \((K - T) \bmod 2\)”.

    Source Code

import sys

def main():
    input_data = sys.stdin.buffer.read().split()
    idx = 0
    N = int(input_data[idx]); idx += 1
    K = int(input_data[idx]); idx += 1
    P = [int(input_data[idx + i]) for i in range(N)]
    
    # 転倒数を BIT で計算
    bit = [0] * (N + 1)
    
    def update(i):
        while i <= N:
            bit[i] += 1
            i += i & (-i)
    
    def query(i):
        s = 0
        while i > 0:
            s += bit[i]
            i -= i & (-i)
        return s
    
    T = 0
    # 右から左へ
    for i in range(N - 1, -1, -1):
        v = P[i]
        # v より小さい値で既に右側にあるものの数
        T += query(v - 1)
        update(v)
    
    if K <= T:
        ans = T - K
    else:
        ans = (K - T) % 2
    
    sys.stdout.write(str(ans) + "\n")

main()

This editorial was generated by claude4.8opus-high.

投稿日時:
最終更新: