E - 隣接スワップで転倒数を減らせ / Reduce Inversions with Adjacent Swaps 解説 by admin
Claude 4.6 Opus (Thinking)Overview
This problem asks you to compute the inversion count of a permutation and, using the fact that a single adjacent swap can decrease the inversion count by at most 1, find the minimum inversion count achievable after at most \(K\) operations.
Analysis
Key Insight: Relationship Between Adjacent Swaps and Inversion Count
Consider the operation of swapping two adjacent elements \(P_i\) and \(P_{i+1}\). The relative order with respect to all other elements remains unchanged. The only relationship that changes is the one between \(P_i\) and \(P_{i+1}\).
- If \(P_i > P_{i+1}\) (an inversion exists), swapping them decreases the inversion count by exactly 1
- If \(P_i < P_{i+1}\) (no inversion), swapping them increases the inversion count by exactly 1
In other words, by choosing swaps wisely, each operation can reliably decrease the inversion count by 1.
Concrete Example
For \(P = [3, 1, 2]\), the inversions are \((3,1)\) and \((3,2)\), giving an inversion count of 2.
- 1st operation: Swap \(P_1=3\) and \(P_2=1\) → \([1, 3, 2]\) (inversion count 1)
- 2nd operation: Swap \(P_2=3\) and \(P_3=2\) → \([1, 2, 3]\) (inversion count 0)
If \(K=1\), the answer is \(1\). If \(K=2\), the answer is \(0\).
Conclusion
Let \(I\) be the current inversion count. The minimum inversion count achievable after at most \(K\) operations is:
\[\max(0, \, I - K)\]
Since the inversion count cannot go below 0, we compare with 0 using \(\max\).
Why a Naive Inversion Count Computation Doesn’t Work
Computing the inversion count by checking all pairs according to the definition takes \(O(N^2)\) time. For \(N \leq 2 \times 10^5\), this requires up to \(4 \times 10^{10}\) comparisons, resulting in TLE. Instead, we use a BIT (Binary Indexed Tree / Fenwick Tree) to compute it in \(O(N \log N)\).
Algorithm
Computing the inversion count using a BIT:
- Scan the array from left to right, processing each element \(P_i\)
- Before inserting \(P_i\), find “the number of already inserted elements that are greater than \(P_i\).” This is obtained by subtracting “the count of elements ≤ \(P_i\)” from \(i\) (the number of elements already inserted)
- Use
query(P[i])on the BIT to get the number of inserted elements ≤ \(P_i\), and add \(i - \text{query}(P_i)\) to the inversion count - Then use
update(P[i])to add \(P_i\) to the BIT
Computing the answer:
- Output \(\text{result} = \max(0, \, I - K)\)
Complexity
- Time complexity: \(O(N \log N)\) (the BIT-based inversion count computation is the bottleneck)
- Space complexity: \(O(N)\) (for the BIT array)
Implementation Notes
Since \(K\) can be as large as \(10^{18}\), you need to use a language or type that supports 64-bit integers (Python naturally handles this with arbitrary-precision integers)
The inversion count itself can be as large as \(\frac{N(N-1)}{2} \approx 2 \times 10^{10}\), so be careful about 32-bit integer overflow (e.g., in C++)
It is standard practice to manage BIT indices as 1-indexed
Source Code
import sys
from collections import defaultdict
def solve():
input_data = sys.stdin.buffer.read().split()
N = int(input_data[0])
K = int(input_data[1])
P = [int(input_data[i + 2]) for i in range(N)]
# Calculate inversion count using BIT (Fenwick Tree)
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
inversions = 0
for i in range(N):
# Count elements already inserted that are greater than P[i]
inversions += i - query(P[i])
update(P[i])
# Each adjacent swap can reduce the inversion count by at most 1
result = max(0, inversions - K)
print(result)
solve()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: