#28485: [C++] Merge Sort


gogogofuxk (RH)

學校 : 國立臺灣大學
編號 : 56934
來源 : [123.193.51.206]
最後登入時間 :
2022-06-03 20:06:56
f315. 4. 低地距離 -- 2020年10月APCS | From: [123.193.51.206] | 發表日期 : 2021-12-13 19:19

滿驚訝竟然沒人分享 Merge Sort 法
使用 Merge Sort 的好處是陣列值不一定要在 $[1,n]$ 之間。

這題可以化約成 find inversion counts of an array
先對每個位置找到「在它之後有多少元素比它小」,然後將相同值的部分相減

以範例測資為例(其中 ans 記錄每個位置後比他小的元素數量):
a     = [3, 1, 2, 1, 3, 2]
ans  = [4, 0, 1, 0, 1, 0]

則最後答案為 (0-0) + (1-0) + (4-1) = 4
0-0 為 兩個 1 中間的答案,1-0 為兩個 2 之間,4-1 為兩個 3 之間。

code:

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define MOD 1000000007
#define MOD2 998244353

vector<int> tmp;
vector<int> ans;

void merge(vector<int>& a, vector<int>& pos, int start, int mid, int end) {
    int p1 = start, p2 = mid+1;
    int offset = start;
    while (p1 <= mid && p2 <= end) {
        if (a[pos[p1]] <= a[pos[p2]]) {
            ans[pos[p1]] += p2 - (mid+1);
            tmp[offset++] = pos[p1++];
        } else {
            tmp[offset++] = pos[p2++];
        }
    }
    while (p1 <= mid) {
        ans[pos[p1]] += p2 - (mid+1);
        tmp[offset++] = pos[p1++];
    }
    while (p2 <= end) {
        tmp[offset++] = pos[p2++];
    }
    for (int i = start; i <= end; i++) {
        pos[i] = tmp[i];
    }
}

void mergeSort(vector<int>& a, vector<int>& pos, int start, int end) {
    if (start == end) {
        return;
    }

    int mid = start + (end - start) / 2;
    mergeSort(a, pos, start, mid);
    mergeSort(a, pos, mid+1, end);
    merge(a, pos, start, mid, end);
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    // merge sort
    int n; cin >> n;
    tmp.resize(2 * n);
    ans.resize(2 * n);

    vector<int> a(2 * n);
    vector<int> pos(2 * n);
    for (int i = 0; i < 2*n; i++) {
        cin >> a[i];
        pos[i] = i;
    }

    mergeSort(a, pos, 0, 2*n-1);

    ll finalAns = 0;
    unordered_set<int> occ;
    for (int i = 0; i < 2*n; i++) {
        if (occ.count(a[i])) {
            finalAns -= ans[i];
        } else {
            finalAns += ans[i];
            occ.insert(a[i]);
        }
    }
    cout << finalAns << '\n';


    return 0;
}
 
ZeroJudge Forum