2021 ICPC ECF 闭幕式
题目背景
经过5h激烈的比拼,2021 ICPC ECF终于接近尾声!
闭幕式上,主办方决定给幸苦的自己颁一个“最顽强拼搏奖”!包括隆今惠在内的若干名馊瀑公司代表上台领奖!
题目描述
领奖台上站着一排共 n n n个人,由于泷津汇先生太过瞩目,我们认为从左到右第 i i i个人的身高相对于龍斤绘是一个整数 h i h_i hi,现在主办方希望将这些人按身高从左到右有序排列。
若每次只能交换相邻两个人的位置,至少需要多少次交换呢?
输入格式
第一行输入一个正整数 n ( 1 ≤ n ≤ 5 × 1 0 5 ) n(1\le n\le 5\times 10^5) n(1≤n≤5×105)。
第二行输入 n n n个整数 h i ( − 2 63 ≤ h i < 2 63 ) h_i(-2^{63}\le h_i< 2^{63}) hi(−263≤hi<263)。
输出格式
一行,输出一个非负整数,表示最少的交换次数。
样例 #1
样例输入 #1
5
3 8 6 0 1
样例输出 #1
7
提示
样例解释:
交换
h
3
,
h
4
h_3,h_4
h3,h4,得
3 8 0 6 1
交换
h
2
,
h
3
h_2,h_3
h2,h3,得
3 0 8 6 1
交换
h
1
,
h
2
h_1,h_2
h1,h2,得
0 3 8 6 1
交换
h
4
,
h
5
h_4,h_5
h4,h5,得
0 3 8 1 6
交换
h
3
,
h
4
h_3,h_4
h3,h4,得
0 3 1 8 6
交换
h
2
,
h
3
h_2,h_3
h2,h3,得
0 1 3 8 6
交换
h
4
,
h
5
h_4,h_5
h4,h5,得
0 1 3 6 8
题解:
题目要求将数据升序排列所产生的最小交换次数,这实际上就是求逆序对的个数
下面提供一种使用归并排序求解逆序对的代码
void merge_sort(int l,int r) {
if (l == r) {
return;
}
int mid = l + (r - l) / 2;
if (l + 1 < r) {
merge_sort(l, mid);
merge_sort(mid + 1, r);
}
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r) {
if (h[i] <= h[j]) {
temp[k++] = h[i++];
}
else {
temp[k++] = h[j++];
ans += mid + 1 - i;
}
}
while(i <= mid)
temp[k++] = h[i++];
while (j <= r)
temp[k++] = h[j++];
for (int ii = 0, jj = l; ii < k; ii++, jj++) {
h[jj] = temp[ii];
}
}
其实核心代码是下面这一句:
ans += mid + 1 - i;
在归并排序的合并过程中,如果 a[ j ] < a[ i ] 表明产生了逆序对。
并且由于a[ i ]后面的数一定大于a [ i ],所以他们一定也和a[ j ]构成逆序对,所以 mid+1-i就等于与a[ j ]构成的逆序对的个数。