給定 0~n-1 的一個排列(n ≤ 5000)。定義逆序對數為 `i
設原序列逆序對數為 `inv0`。將首元素 `x = a[0]` 移到末尾:
#includeusing namespace std; const int MAXN = 5005; int a[MAXN], tmp[MAXN]; long long inv; void merge_sort(int l, int r) { if (l >= r) return; int mid = (l + r) >> 1; merge_sort(l, mid); merge_sort(mid+1, r); int i = l, j = mid+1, k = l; while (i <= mid && j <= r) { if (a[i] <= a[j]) tmp[k++] = a[i++]; else { tmp[k++] = a[j++]; inv += mid - i + 1; // a[i..mid] 都 > a[j] } } while (i <= mid) tmp[k++] = a[i++]; while (j <= r) tmp[k++] = a[j++]; copy(tmp+l, tmp+r+1, a+l); } int main() { int n; while (scanf("%d", &n) == 1) { for (int i = 0; i < n; ++i) scanf("%d", &a[i]); inv = 0; merge_sort(0, n-1); long long ans = inv; for (int k = 0; k < n-1; ++k) { inv += n - 1 - 2LL * a[k]; ans = min(ans, inv); } printf("%lld\n", ans); } return 0; }
循環移動逆序對最小值。利用排列 0~n-1 的特殊性質,首元素移動的逆序對變化量有閉式公式,避免了重複計算。歸並排序求初始逆序對 + O(n) 遞推,完美應對 n=5000。